Substitution cipher:Which one? - c++

I'm a beginner and I have a question(somehow silly and stupid :) )...Today I decided to challenge myself and I came around the challenge that wanted me to create a program that ciphers (or encrypts) the message using the substitution cipher method...I solved the challenge by myself but mine is way different than the solution itself...I just want to know which one is better and why? and also is there anything I missed in my own code?
So here is the code I've written:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string secretMessage {};
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string key {"XZNLWEBGJHQDYVTKFUOMPCIASRxznlwebgjhqdyvtkfuompciasr"};
cout << "Enter your secret message: ";
getline(cin, secretMessage);
//Encryption
for(size_t i{0}; i<secretMessage.length(); ++i){
for(size_t j{0}; j<alphabet.length(); ++j){
if (secretMessage.at(i) == alphabet.at(j)){
secretMessage.at(i) = key.at(j);
break;
}
}
}
cout << "Encrypting The Message..." << endl;
cout << "Encrypted Message: " << secretMessage << endl;
//Decryption
for(size_t i{0}; i<secretMessage.length(); ++i){
for(size_t j{0}; j<key.length(); ++j){
if (secretMessage.at(i) == key.at(j)){
secretMessage.at(i) = alphabet.at(j);
break;
}
}
}
cout << "\nDecrypting The Encryption..." << endl;
cout << "Decrypted: " << secretMessage << endl;
return 0;
}
And here is the solution:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string secretMessage {};
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string key {"XZNLWEBGJHQDYVTKFUOMPCIASRxznlwebgjhqdyvtkfuompciasr"};
string encryptedMessage {};
string decryptedMessage {};
cout << "Enter your secret message: ";
getline(cin, secretMessage);
cout << "\nEncrypting Message..." << endl;
//Encryption
for(char c:secretMessage){
size_t position = alphabet.find(c);
if (position != string::npos){
char newChar {key.at(position)};
encryptedMessage += newChar;
} else{
encryptedMessage += c;
}
}
cout << "Encrypted Message: " << encryptedMessage << endl;
//Decryption
cout << "\nDecrypting Message..." << endl;
for(char c:encryptedMessage){
size_t position = key.find(c);
if (position != string::npos){
char newChar {alphabet.at(position)};
decryptedMessage += newChar;
} else{
decryptedMessage += c;
}
}
cout << "Decrypted Message: " << decryptedMessage << endl;
return 0;
}
Note:I have also included the decryption part too

I find both code snipets rather complex.
Please have a look at this more easy solution
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
// The encoding alphabet and key
constexpr std::string_view alphabet{ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ _" };
constexpr std::string_view key{ "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba_ " };
// String to encrypt
std::string message{"Hello world"};
// Here we will store the result
std::string result;
std::transform(message.begin(), message.end(), std::back_inserter(result), [&key, &alphabet](const char c)
{ size_t pos{ alphabet.find(c) }; return (pos != std::string::npos) ? key[pos] : '_'; });
// Show result
std::cout << "\nEncrypted: " << result << "\n";
message = result;
result.clear();
std::transform(message.begin(), message.end(), std::back_inserter(result), [&key, &alphabet](const char c)
{ size_t pos{ alphabet.find(c) }; return (pos != std::string::npos) ? key[pos] : '_'; });
// Show result
std::cout << "\nDecrypted: " << result << "\n";
return 0;
}
This is using more modern C++ language elements. Encrypting and decrypting is implemented via one std::transform statement each.
Of course you should never use such encoding in real live, because the key is visible in the exe file.
Anyway, maybe it helps you to have some more ideas . . .

Related

Error while Pushing Elements from a std::string onto a Stack of String Type

I get this error while trying to loop through a string to push each element onto a stack of string type s1 in my isPalindrome() function.
no instance of overloaded function "std::stack<_Ty, _Container>::push
[with _Ty=std::string, _Container=std::deque>]" matches the argument list
When I assign, the element that is at the top of the stack to a string variable an error pops up:
'std::stack>>::top':
non-standard syntax; use '&' to create a pointer to member
Why does it mention std::deque?
#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
class Palindrome
{
public:
Palindrome();
void inputString();
std::string convert2lower();
bool isPalindrome();
private:
std::string userstring;
std::stack<std::string> s1;
};
Palindrome::Palindrome()
{}
void Palindrome::inputString()
{
std::cout << "Enter a string: ";
std::getline(std::cin,userstring);
}
std::string Palindrome::convert2lower()
{
userstring.erase(remove(userstring.begin(), userstring.end(), ' '), userstring.end());
userstring.erase(std::remove_if(userstring.begin(), userstring.end(), ispunct), userstring.end());
transform(userstring.begin(), userstring.end(), userstring.begin(), tolower);
return userstring;
}
bool Palindrome::isPalindrome()
{
size_t n = userstring.size();
for (size_t i = 0; i < n; ++i)
{
s1.push(userstring[i]);
}
std::string reversed;
for (size_t i = 0; i < n; ++i)
{
std::string temp = s1.top;
reversed.insert(i,temp);
s1.pop();
}
if (reversed == userstring)
{
return true;
}
return false;
}
int main()
{
Palindrome p1;
p1.inputString();
std::cout << "\nCalling convert2lower(): " << std::endl;
std::cout << "The new string is " << p1.convert2lower() << std::endl;
std::cout << "\nCalling isPalindrome(): " << std::endl;
if (!p1.isPalindrome())
{
std::cout << "String is NOT a Palindrome!" << std::endl;
}
else
{
std::cout << "String is a Palindrome!" << std::endl;
}
}
Here is your code fixed with the absolute minimum changes...
#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
class Palindrome
{
public:
Palindrome();
void inputString();
std::string convert2lower();
bool isPalindrome();
private:
std::string userstring;
std::stack<char> s1;
};
Palindrome::Palindrome()
{}
void Palindrome::inputString()
{
std::cout << "Enter a string: ";
std::getline(std::cin, userstring);
}
std::string Palindrome::convert2lower()
{
userstring.erase(remove(userstring.begin(), userstring.end(), ' '), userstring.end());
userstring.erase(std::remove_if(userstring.begin(), userstring.end(), ispunct), userstring.end());
transform(userstring.begin(), userstring.end(), userstring.begin(), tolower);
return userstring;
}
bool Palindrome::isPalindrome()
{
size_t n = userstring.size();
for (size_t i = 0; i < n; ++i)
{
s1.push(userstring[i]);
}
std::string reversed;
for (size_t i = 0; i < n; ++i)
{
char temp = s1.top();
reversed.insert(i, &temp, 1);
s1.pop();
}
if (reversed == userstring)
{
return true;
}
return false;
}
int main()
{
Palindrome p1;
p1.inputString();
std::cout << "\nCalling convert2lower(): " << std::endl;
std::cout << "The new string is " << p1.convert2lower() << std::endl;
std::cout << "\nCalling isPalindrome(): " << std::endl;
if (!p1.isPalindrome())
{
std::cout << "String is NOT a Palindrome!" << std::endl;
}
else
{
std::cout << "String is a Palindrome!" << std::endl;
}
}
Here are answers to your questions:
no instance of...this is caused by using string instead of char as the stack type.
non standard syntax...this is because you left the () off of pop.
deque is mentioned because stack is a specialization of deque.

Reading and Writing from same file?

i am storing some data in the file but after
if (titlemap.count(words[i]) == 1)
is reached i reopened the file and reading all data in a vector and then storing updated data but
But actually the program is not going into the below loop.
for (int j = 0; j < vec.size(); j++)
Can anyone suggest why is it so? I am very confused and frustrated
// Cmarkup1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include"Markup.h"
#include <msxml.h>
#include <ctime>
#include <unordered_map>
#include <cctype>
#include <string>
#include <functional>
#include <algorithm>
#include "functions.h"
#include <map>
#include <fileapi.h>
using namespace std;
int main()
{
// Open the file for parsing.
ofstream wfile("title.txt");
bool check = false;
string delimiter = " ,:,";
int results = 0, pages = 1;
time_t timer;
timer = clock();
CMarkup xmlfile;
unordered_map<string, string> titlemap;
unordered_map<string, string> textmap;
vector <string> words;
xmlfile.Load(MCD_T("simplewiki-latest-pages-articles.xml"));
xmlfile.FindElem();
xmlfile.IntoElem();
int line=0;
while (xmlfile.FindElem(MCD_T("page"))) {
xmlfile.IntoElem();
xmlfile.FindElem(MCD_T("title"));
MCD_STR(title);
title = xmlfile.GetData();
string str(title.begin(), title.end());
transform(str.begin(), str.end(), str.begin(), ::tolower);
split(words, str, is_any_of(delimiter));
for (int i = 0; i < words.size(); i++) {
if (titlemap.count(words[i]) == 1) {
ifstream rfile;
rfile.open("title.txt");
vector<string> vec;
string line;
while (getline(rfile, line)) {
vec.push_back(line);
}
for (int j = 0; j < vec.size(); j++) {
if (words[i] == vec[j]) {
cout << vec[j] <<"Checking"<< endl;
wfile << vec[j] << ",page" << pages << endl;
}
else
wfile << vec[j] << endl;
//wfile.close();
}
}
else {
//wfile.open("title.txt");
keeponlyalphabets(words[i]);
titlemap.insert(make_pair(words[i], words[i]));
wfile << words[i] <<"-page"<<pages<< endl;
++line;
}
}
words.clear();
//cout << str << endl;
//xmlfile.FindElem(MCD_T("text"));
//MCD_STR(text);
//text = xmlfile.GetData();
//string str1(text.begin(), text.end());
//transform(str1.begin(), str1.end(), str1.begin(), ::tolower);
//str1 = keeponlyalphabets(str1);
//removestopwords(str1);
//textmap.insert(make_pair(str1, str1));
//cout << str1 << endl;
if (pages > 100)
break;
pages++;
xmlfile.OutOfElem();
}
wfile.close();
// for (auto it : titlemap)
// cout << it.first << endl;
cout << "Total lines are as: "<<line << endl;
/*string input;
cout << "press s to seach the data" << endl;
getline(cin, input);
if (input == "s") {
string key;
cout << "Enter Key" << endl;
cin >> key;
transform(key.begin(), key.end(), key.begin(), ::tolower);
size_t temp;
cout << endl;
for (auto it = data.begin(); it != data.end(); it++) {
//temp = it->first.find(key);
//cout << temp;
if (it->first.find(key) != std::string::npos) {
cout << it->second << endl;
results++;
}
}
}
else
cout << "Invalid Character Exiting....." << endl;
timer = clock() - timer;
cout << "Total time taken by the process is: " << (float)timer / CLOCKS_PER_SEC << endl;
cout << " Total Results : " << results << endl;
*/
return 0;
}
You have separate streams opened against the file, with separate buffers on each. writeing to a file only actually writes to disk infrequently (typically when a buffer fills, which may take a while for small writes, and always just before the file is closed). So when you re-open the file for read, it won't see anything still stuck in user-space buffers.
Just add:
wfile.flush()
prior to opening for read, to ensure the buffers are flushed to disk and available to the alternate handle.

Hangman w/ Functions - Compile Error - No Match for Call To

I've been trying to get this Hangman using functions (from Michael Dawson's book) program to work, but I have this one error that I don't really understand. I realize my code code could have a variety of bad practices, but please go easy on me as I am a newb. I feel like I am almost there but I'm having trouble figuring out this one error. I am using CodeBlocks. The error is:
32|error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string}) (std::__cxx11::basic_string::size_type, char)'|
//Hangman from Michael Dawson's code
//Uses functions to create the program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>
using namespace std;
//FUNCTION DECLARATION
string pickword();
char playerGuess();
void isitinthere();
char guess = 0;
string soFar = "word";
string used = "";
int wrong = 0;
int main()
{
const int MAX_WRONG = 8;
string WORD = pickword();
soFar = WORD;
soFar(WORD.size(), '-');
used = "";
cout << "Welcome to Hangman! Godspeed!" << endl;
while ((wrong < MAX_WRONG) && (soFar != WORD))
{
cout << "\n\nYou have " << (MAX_WRONG - wrong);
cout << " incorrect guesses left.\n";
cout << "\nYou've used the following letters:\n" << used << endl;
cout << "\nSo far, the word is:\n" << soFar << endl;
}
playerGuess();
while (used.find(guess) != string::npos)
{
cout << "\nYou've already guessed " << guess << endl;
cout << "Enter your guess: ";
cin >> guess;
guess = toupper(guess);
}
used += guess;
isitinthere();
if (wrong == MAX_WRONG)
{
cout << "\nYou've been hanged!";
}
else
{
cout << "\nYou guessed it!";
}
cout << "\nThe word was " << WORD << endl;
return 0;
}
//FUNCTION DEFINITION
string pickword()
{
srand(static_cast<unsigned int>(time(0)));
vector<string> words;
words.push_back("INDUBITABLY");
words.push_back("UNDENIABLY");
words.push_back("CRUSTACEAN");
words.push_back("RESPONSIBILITY");
words.push_back("MISDEMEANOR");
words.push_back("FORENSIC");
words.push_back("BALLISTIC");
words.push_back("PARADIGM");
words.push_back("TROUBARDOR");
words.push_back("SUPERCALIFRAGILISTICEXPIALLADOCIOUS")
random_shuffle(words.begin(), words.end());
theword = words[0];
return theword;
}
char playerGuess()
{
cout << "\n\nEnter your guess: ";
cin >> guess;
guess = toupper(guess);
return guess;
}
void isitinthere()
{
if (WORD.find(guess) != string::npos)
{
cout << "That's right! " << guess << " is in the word.\n";
for (int i = 0; i < WORD.length(); ++i)
{
if (WORD[i] == guess)
{
soFar[i] = guess;
}
}
}
else
{
cout << "Sorry, " << guess << "isn't in the word. \n";
++wrong;
}
}
Thanks in advance for your help!
Here is a simple program that should solve your question.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cctype>
// since you must have function here are some
bool removeGuessFromWord(std::string& word, const char guess);
bool isGuessInWord(const std::string& word, const char guess);
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess);
// this is a simple program that should solve your question. It is not optimized for speed or efficency.
int main()
{
std::vector<std::string> wordList = {"dog","cat","rat"}; // vector of words to select from and use as the word in hangman
std::vector<char> guessList; // empty vector of gusses
// Note that I assume a MAX_GUESS_COUNT of 0 means no guesses are allowed
const unsigned int MAX_GUESS_COUNT = 4U; // number of guesses your allowed
std::srand(time(0)); // use current time as seed for random generator
std::string word = wordList.at(std::rand()%wordList.size()); // get a random word in the list
std::string letersLeft = word; // keep track of what letters will still need to remove
std::cout << "Welcome to Hangman! Godspeed!" << std::endl;
char guess = 0;
for(unsigned int numBadGusses=0U; numBadGusses<MAX_GUESS_COUNT && letersLeft.size()>0U; guess = 0)
{
std::cin>>guess;
if(std::isprint(guess) == 0)
{
// may want more error checking
std::cout << "You ented a non-printable charecter" << std::endl;
}
else if(isGuessInWord(word, guess))
{
// this was a good guess because the charecter is still in the word
// so remove all the remaining chars of this type from the word
if( removeGuessFromWord(letersLeft,guess) )
{
std::cout << guess << " was a good guess" << std::endl;
}
else
{
std::cout << guess << " was a good guess, but you already guessed it once" << std::endl;
}
}
else if(hasAlreadyGuessed(guessList, guess))
{
std::cout << "You've already guessed " << guess << std::endl;
}
else
{
// this was a new bad guess
guessList.push_back(guess);
numBadGusses++; // Note that this isn't technicly needed and could use size of vector
std::cout << guess << " was a bad guess" << std::endl;
}
}
if(letersLeft.size() == 0U)
{
std::cout<<"You Win"<<std::endl;
}
else
{
std::cout<<"You Lose"<<std::endl;
}
std::cout << "The word was "<< word << std::endl;
return 0;
}
bool removeGuessFromWord(std::string& word, const char guess)
{
return word.erase(std::remove(word.begin(), word.end(), guess), word.end()) != word.end() ? true : false;
}
bool isGuessInWord(const std::string& word, const char guess)
{
return word.find(guess) != std::string::npos ? true: false;
}
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess)
{
return std::find(gussList.begin(), gussList.end(), guess) != gussList.end() ? true: false;
}

C++ Trouble Modifying A String

So in this program I'm trying to go through word by word and make it only lowercase letters, no whitespace or anything else. However, my string "temp" isn't holding anything in it. Is it because of the way I'm trying to modify it? Maybe I should try using a char * instead? Sorry if this is a stupid question, I'm brand new to c++, but I've been trying to debug it for hours and can't find much searching for this.
#include <string>
#include <iostream>
#include <fstream>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[]) {
/*if (argc != 3) {
cout << "Error: wrong number of arguments." << endl;
}*/
ifstream infile(argv[1]);
//infile.open(argv[1]);
string content((std::istreambuf_iterator<char>(infile)),
(std::istreambuf_iterator<char>()));
string final;
string temp;
string distinct[5000];
int distinctnum[5000] = { 0 };
int numdist = 0;
int wordcount = 0;
int i = 0;
int j = 0;
int k = 0;
int isdistinct = 0;
int len = content.length();
//cout << "test 1" << endl;
cout << "length of string: " << len << endl;
cout << "content entered: " << content << endl;
while (i < len) {
temp.clear();
//cout << "test 2" << endl;
if (isalpha(content[i])) {
//cout << "test 3" << endl;
if (isupper(content[i])) {
//cout << "test 4" << endl;
temp[j] = tolower(content[i]);
++j;
}
else {
//cout << "test 5" << endl;
temp[j] = content[i];
++j;
}
}
else {
cout << temp << endl;
//cout << "test 6" << endl;
++wordcount;
final = final + temp;
j = 0;
for (k = 0;k < numdist;k++) {
//cout << "test 7" << endl;
if (distinct[k] == temp) {
++distinctnum[k];
isdistinct = 1;
break;
}
}
if (isdistinct == 0) {
//cout << "test 8" << endl;
distinct[numdist] = temp;
++numdist;
}
}
//cout << temp << endl;
++i;
}
cout << wordcount+1 << " words total." << endl << numdist << " distinct words." << endl;
cout << "New output: " << final << endl;
return 0;
}
You can't add to a string with operator[]. You can only modify what's already there. Since temp is created empty and routinely cleared, using [] is undefined. The string length is zero, so any indexing is out of bounds. There may be nothing there at all. Even if the program manages to survive this abuse, the string length is likely to still be zero, and operations on the string will result in nothing happening.
In keeping with what OP currently has, I see two easy options:
Treat the string the same way you would a std::vector and push_back
temp.push_back(tolower(content[i]));
or
Build up a std::stringstream
stream << tolower(content[i])
and convert the result into a string when finished
string temp = stream.str();
Either approach eliminates the need for a j counter as strings know how long they are.
However, OP can pull and endrun around this whole problem and use std::transform
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
to convert the whole string in one shot and then concentrate on splitting the lower case string with substring. The colons in front of ::tolower are there to prevent confusion with other tolowers since proper namespacing of the standard library has been switched off with using namespace std;
Off topic, it looks like OP is performing a frequency count on words. Look into std::map<string, int> distinct;. You can reduce the gathering and comparison testing to
distinct[temp]++;

how can I find the sequence number (index) of word in such a paragraph c++?

I'm working on a project which needs to find the number of words and the indices of each word in the paragraph ...I have written the code which is counting the number of word in a string but I stuck with finding the indices of words,
such as : Hi John How are you I miss you ..
I need to print the indices like : 0 1 2 3 4 5 6 7
here is the code:
int _tmain(int argc, _TCHAR* argv[])
{
int count_words(std::string);
std::string input_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
int number_of_words=1;
int counter []={0};
for(int i = 0; i < input_text.length();i++)
if(input_text[i] == ' ')
number_of_words++;
std::cout << "Number of words: " << number_of_words << std::endl;
//std:: cout << number_of_words << std::endl;
system ("PAUSE");
}
Hopefully this helps. Edited to include use of count_words function.
#include <iostream>
#include <sstream>
void count_words(std::string);
int main(){
std::string input_text, output_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
count_words(input_text);
system ("PAUSE");
return 0; //MUST RETURN AN INTEGER VALUE FROM 'INT MAIN'
}
void count_words(std::string inputString){
std::string output_text;
std::stringstream indexes;
int number_of_words=0; //If there are no words, it would be false, make it 0.
//int counter []={0}; //This serves no purpose.
if(!inputString.empty()){// test to make sure it isn't empty.
number_of_words++;
for(int i = 0; i < inputString.length();i++){ // For loops should have curly braces {} containing their statement.
if(inputString[i] == ' '){
number_of_words++;
}
if((isalpha(inputString[i]))&&inputString[i-1]==' '){ //test for following space separated word
indexes << i << " ";
}
}
}
output_text = indexes.str(); //convert stringstream to string
std::cout << "Number of words: " << number_of_words << std::endl;
//std:: cout << number_of_words << std::endl; //duplicate info
std::cout << "Indexes: " << output_text << std::endl;
}
I'm not sure if i understand the question. You only need print the "indices"?? like this? (Using your own code)
#include <iostream>
#include <vector>
#include <string>
void stringTokenizer(const std::string& str, const std::string& delimiter, std::vector<std::string>& tokens) {
size_t prev = 0, next = 0, len;
while ((next = str.find(delimiter, prev)) != std::string::npos) {
len = next - prev;
if (len > 0) {
tokens.push_back(str.substr(prev, len));
}
prev = next + delimiter.size();
}
if (prev < str.size()) {
tokens.push_back(str.substr(prev));
}
}
int main()
{
std::vector <std::string> split;
std::string input_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
stringTokenizer(input_text, " ", split);
int number_of_words = 0;
for (std::vector<std::string>::iterator it = split.begin(); it != split.end(); it++, number_of_words++) {
std::cout << *it << " " << number_of_words << std::endl;
}
}