C++ Caesar Cipher encryption - c++

can anyone explain how this set of code works ?
string LoginAccess::decryptPass(string pass) {
int count = 0;
while (count < pass.length()) {
if (isalpha(pass[count])) {
//For Caps lock
if (pass[count] > 64 && pass[count] < 91) {
if (pass[count] < 88) {
pass[count] += 3;
} else if (pass[count] == 88) {
pass[count] = 'A';
} else if (pass[count] == 89) {
pass[count] = 'B';
} else
pass[count] = 'C';
//For small char
} else {
if (pass[count] < 120) {
pass[count] += 3;
} else if (pass[count] == 120) {
pass[count] = 'a';
} else if (pass[count] == 121) {
pass[count] = 'b';
} else
pass[count] = 'c';
}
}
count++;
}
return pass;
}
What do the numbers like 64, 91, etc mean?
Why only set it a, b, c ? What happens to the rest of the alphabet?

This function loops the string pass, incrementing count to use as an index for the array. The code is decoding a Ceasar cipher, where each letter is shifted down the alphabet a certain number of places, in this case, three.
It compares the current character (pass[count]) with ASCII character codes. Each letter and punctuation mark has a number associated with it. You can see a chart of characters on this page. As you can see there, the capital letters ('A' through 'Z') span 65 to 90, and the lowercase ('a' through 'z') 97 to 122.
So the code checks whether the letter falls in upper or lower case. There it will by default move the letter three spaces forward, but if it did that with the last three letters of the alphabet, that would push into the number of punctuation. So special coditions are put in to check for that. If pass[count] is 88, the character 'X', it is manually set to 'A', the number 65. If it were incremented by three it would become 91, the character, '['.
There are some weaknesses in the code, as it only supports letters. If punctuation marks were in the pass string, they would be changed into another random punctuation, for no reason from the user's perspective.

Related

How to find the duplicate

/* I have written a code for a simple hangman based on instructions given, I just want to know how to detect the duplicated inputs. For this code, It only detects correct letters and the length
For example:
user input: HAM
H
A
A
HANGMAN! */
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
// Word to be guessed can be assumed to be at most 20 characters long (including end-of-string null character)
char HangmanWord[20];
// Variable to store current guess
char GuessLetter;
int count = 0;
std::cin >> HangmanWord;
//char guessedletter[strlen(HangmanWord)];
//int j = 0;
bool valid = true;
// Check that input word only consists of uppercase English letters
for (int i = 0; i < strlen(HangmanWord); i++)
{
if ((HangmanWord[i] > 'Z') || (HangmanWord[i] < 'A'))
{
valid = false;
break;
}
}
while (valid == true)
{
std::cin >> GuessLetter; //Takes the Guess letter
if ((GuessLetter > 'Z') || (GuessLetter < 'A')) //Check that guessed letter is uppercase
{
break;
}
else
{
for (int i = 0; i < strlen(HangmanWord); i++) //loop to check every letter in word
{
if (GuessLetter == HangmanWord[i]) { //if the letter is equal to any letter in the word the count increases
count++;
break;
}
if (i == strlen(HangmanWord) - 1) { //If no letter is equal to any letter in the word the program exits
valid = false;
}
}
if (count == strlen(HangmanWord)) { //Checks if all letters were guessed and exits the loop after
valid = false;
}
}
}
if (count == strlen(HangmanWord)) { //Checks if all letters were guessed correct to print Hangman
cout << "HANGMAN!\n";
valid = false;
}
If you want to detect whether a letter has already been input, you can work with ASCII characters being represented by numbers. Assuming we limit ourselves to uppercase letters, 'A' is 65 and 'Z' is 90.
We can do math with these. 'A' - 'A' is 0 and 'C' - 'A' is 2.
We also know that arrays are indexed starting from zero.
We can put these things together to create an array of boolean values, and flag them as letters are guessed.
std::array<std::bool, 26> already_guessed;
std::fill(already_guess.begin(), already_guessed.end(), false);
And we can then check on whether a letter has been guessed by looking it up. Consider, for instance, checking whether 'D' has been guessed. They should start out false, as nothing has been guessed at the beginning.
already_guessed['D' - 'A']
If it hasn't, we can mark it as guessed:
already_guessed['D' - 'A'] = true

Caesar cipher encoding in C++: chars won't loop back to 'a' or 'A'

I'm working on coding a ceasar cipher that reads plaintext from a .txt, encrypts the plaintext and writes to a second .txt, then reads the second .txt and decrypts it to a third .txt. Everything is working except the encryption of characters near the end of the alphabet. When a character reaches 'z' or 'Z' it should loop back to 'a' or 'A'. Below is a snippet of code from my encoding function, this is the only bit that's causing issues.
if (isalpha(inputString[i])) { //use isalpha() to ignore other characters
for (int k = 0; k < key; k++) { //key is calculated in another function, 6 in this case
if (inputString[i] == 'z') //these statements don't seem to work
encryptedString[i] = 'a';
else if (inputString[i] == 'Z')
encryptedString[i] = 'A';
else //this part works correctly
encryptedString[i] ++;
}
}
Input:
THE quick brown fox
Jumped over the----
House or moon or some-thing.
Expected output:
ZNK waoiq hxuct lud
Pasvkj ubkx znk----
Nuayk ux suut ux yusk-znotm.
Actual Output:
THE q{ick bro}n fo~
J{mped o|er the----
Ho{se or moon or some-thing.
Key: 6
You are modifying encryptedString and then basing your "loop-over" decision on inputString.
I suspect that you want to firstly initialize encryptedString from inputString, and then work only on encryptedString.
It looks, to me, like you should do it like this:
encryptedString[i] = inputString[i]; // initialize encryptedString
if (isalpha(inputString[i]))
{
for (int k = 0; k < key; k++)
{
if (encryptedString[i] == 'z') // read from encryptedString instead of inputString
encryptedString[i] = 'a';
else if (encryptedString[i] == 'Z') // read from encryptedString instead of inputString
encryptedString[i] = 'A';
else
encryptedString[i] ++;
}
}

Keeping Tally of Characters in Arrays

I'm working on a Caesar Cipher program for an assignment and I have the general understanding planned out, but my function for determining the decipher key is unnecessarily long and messy.
while(inFile().peek != EOF){
inFile.get(character);
if (character = 'a'|| 'A')
{ aCount++; }
else if (character = 'b' || 'B')
{ bCount++; }
so on and so on.
What way, if it's possible, can I turn this into an array?
You can use the following code:
int count [26] = {0};
while(inFile().peek != EOF){
inFile.get(character);
if (int (character) >=65 || int (character) <=90)
{ count [(int (character)) - 65] ++; }
else if (int (character) >=97 || int (character) <=122)
{ count [(int (character)) - 97] ++; }
}
P.S. This is checking for the ASCII value of each character and then increment its respective element in the array of all characters, having 0 index for A/a and 1 for B/b and so on.
Hope this helps...
P.S. - There was an error in your code, = is an assignment operator and == is a conditional operator and you do not assign value in if statement, you check for condition... So always use == to check for equality...
You can use an array in the following manner
int letterCount['z'] = {0}; //z is the highest letter in the uppercase/lowercase alphabet
while(inFile().peek != EOF){
inFile.get(character);
if (character > 'A' && character < 'z')
letterCount[character]++;
}
You can also use a hashmap like this
#include <unordered_map>
std::unordered_map<char,int> charMap;
while(inFile().peek != EOF){
inFile.get(character);
if (charMap.find(character) == charMap.end())
charMap[character] = 1;
else
charMap[character] = charMap[character] + 1;
}
In case you do not know, a hashmap functions as an array, where the index can be any class you like, as long as it implements a hash function.

C++ caesar cipher — understanding ascii keys

I am currently doing a caesar cipher program. It should encrypt for both lower and upper case.
e.g
If I typed in a, it will then shift the keys by 3 and the final output will become d.
Take a look at my codes
char c;
c = (((97-52)+3) % 26) + 52;
cout << c;
The letter 'a' has an ASCII code of 97.
So by right
1) ((97-52)+3) will give you 48
2) 48 % 26 will give you 8 since 48/26 will give you a remainder of 8.
3) 8 + 52 = 60(which will by right give you a value of '>' according to the ascii table)
but my output that I have got is J and I don't understand which am I getting the output of 'J' instead of '>'
My concepts might be wrong so I need help.
Let me link ASCII chart I use first: http://pl.wikipedia.org/wiki/ASCII
The website is polish, but table itself is in english.
I think it's plainly obvious that problem is the equatation you use:
(((letter-52)+3) % 26) + 52;
Actually first letter in ASCII is 65(hexadecimal 0x41 - follow with the chart provided).
Your idea with the modulo would be fine, if there were no chars between letter blocks in ASCII. But there are (again check up chart).
That is why you should manually check if the sign:
is a capital letter: if (letter >= 0x41 && letter <= 0x5a)
is a non-capital: if (letter >= 0x61 && letter <= 0x7a)
Usually when making Ceasar cipher, you should follow these:
Replace a capital letter with capital letter moved in the alphabet by a given number.
If the letter would be out of alphabet scope, continue iteration from the start of alphabet (X moved 5 to the right would give C).
Other chars stay the same
Now let's implement this (in code I'll use letter values of chars - to avoid mistakes):
#include <iostream>
#include <cstdlib>
using namespace std;
string Ceasar(string input, int offset)
{
string result = "";
for (int i = 0; i < input.length(); ++i)
{
// For capital letters
if (input[i] >= 'A' && input[i] <= 'Z')
{
result += (char) (input[i] - 'A' + offset) % ('Z' - 'A') + 'A';
continue;
}
// For non-capital
if (input[i] >= 'a' && input[i] <= 'z')
{
result += (char) (input[i] - 'a' + offset) % ('z' - 'a') + 'a';
continue;
}
// For others
result += input[i];
}
return result;
}
int main()
{
cout << Ceasar(string("This is EXamPLE teXt!?"), 8).c_str();
system("PAUSE");
}

C++ manipulating numbers in ASCII to stay only in range of letters

#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}