I am trying to create a Caesar cipher using C++. I have the program read in a text file but I need it to encrypt the text and output to the screen.
This is my encryption code but I can't seem to get it to work. I have only just started using C++ and not really sure where to go from here.
cout << "enter a value between 1-26 to encrypt the text: ";
cin >> shift;
while ((shift <1) || (shift >26)) {
cout << "Enter a value between 1 and 26!: ";
cin >> shift;
}
int size = strlen(text);
int i=0;
for(i=0; i<size; i++) {
cipher[i] = (text[i]);
if (islower(text[i])) {
if (text[i] > 122) {
cipher[i] = ( (int)(text[i] - 26) + shift);
}
} else if (isupper(text[i])) {
if (text[i] > 90) {
cipher[i] = ( (int)(text[i] - 26) + shift);
}
}
}
cipher[size] = '\0';
cout << cipher << endl;
First of all, your algorithm is wrong.
If we assume ASCII input then you need to encrypt the values that are between 32 (i.e. space) and 126 (i.e. tilde ~), inclusive. You do this by adding the key (a single number) to the value. If the result is greater than 126 (your highest available character) you need to wrap around and start counting from 32. This means 126 + 1 = 32, 126 + 2 = 33, etc. Look up "modulo".
I recommend you look-up the word "debugging". Generally, when you have an algorithm you write code that matches the algorithm as best you can. If the results are not the expected ones then you step line by line using the debugger until you find the line were your expected results and your code's result no longer match.
reformatted, made compilable ad fixed algorithm (to what i think was tried to achieve)
#include <iostream>
using namespace std;
char text[] = {"This is my encryption code but I can't seem to get it to work. "
"I have only just started using C++ and not really sure where "
"to go from here."};
char cipher[sizeof(text)];
void main()
{
int shift;
do {
cout << "enter a value between 1-26 to encrypt the text: ";
cin >> shift;
} while ((shift <1) || (shift >26));
int size = strlen(text);
int i=0;
for(i=0; i<size; i++)
{
cipher[i] = text[i];
if (islower(cipher[i])) {
cipher[i] = (cipher[i]-'a'+shift)%26+'a';
}
else if (isupper(cipher[i])) {
cipher[i] = (cipher[i]-'A'+shift)%26+'A';
}
}
cipher[size] = '\0';
cout << cipher << endl;
}
A few things:
You are checking if the character islower and then checking if the
ascii value is > 122. This will never be true. In the default
locale (standard ascii), islower() will only be true if the ascii
value is in the range [97, 122] (a-z). The same goes for
isupper(). It only returns true for ascii values between 65 and
90, inclusive.
You are already working with ascii values anyway, so islower() and isupper() may be redundant. Those are equivalent to doing bounds checking on the ranges, i.e. text[i] >= 97 && text[i] <= 122. They are useful shortcuts, but don't base your code around them if you can simplify.
Your code never adds the caesar shift if the value is <= 90/122, so you will never shift anything.
Related
In my intro class, I'm tasked with translating a phone number that may have letters in it, back to a pre-determined list of numbers (like 1-800-COLLECT would display as 1-800-2655328) and currently, I can translate the letters to numbers but for whatever reason, the non-letters in the phone numbers arent being translated. This is the main function:
int main()
{
string original;
cout << "Please enter a phone number with letters: ";
getline(cin, original);
cout << "This is your number without letters: ";
for (int i = 0; i < original.length(); i++)
{
if (original[i] < 0 || original[i] > 9)
{
translate(original[i]);
}
else
cout << original[i];
}
}
The translate function simply takes whatever element its fed and, if it falls between Aa - Zz it will display a predetermined number. (Aa - Cc would display the number 2, etc) So far it works for translating, as when I put in "1800GOTJUNK" it returns "4685865" fine, but won't acknowledge the "1800" before it, I think there's something wrong with how I'm structuring the if and for statements to display everything correctly, can someone give me some advice?
This:
if (original[i] < 0 || original[i] > 9)
Is comparing against the ASCII codes 0 and 9, not the actual characters.
It should be:
if (original[i] < '0' || original[i] > '9')
I am trying to create a code that will use the entire printable ASCII Character set. My problem is that when it comes to characters that will be a number higher than 126 they print as '?', except for 'r', which prints correctly. Why does my code allow 'r' to roll back up to a printable character but not any characters after that? (stuvwxyz{|}~)
" Please enter your password.
abcdefghijklmnopqrstuvwxyz{|}~
nopqrstuvwxyz{|}~!???????????? "
#include <iostream>
#include <string>
using namespace std;
void encrypt(string password)
{
int count = 0;
char i;
for (count = 0; count < password.length(); count++)
{
i = password.at(count) + 13;
if (i >= 127)
{
i = 32 + (i - 126);
cout << i;
}
else
cout << i;
}
return;
}
int main()
{
string password;
cout << "Please enter your password." << endl;
cin >> password;
encrypt(password);
cout << "\n";
return 0;
}
Your target platform has signed char, so valid values in char are of range -128 .. +127.
Thus your if (i >= 127) will cover only 'r' (value 114), for 's' the i is equal to -128, not +128. And your if will be false and you will output -128 char value.
One quick-fix is to declare i as unsigned char to operate rather on range +0 .. +255. If you are going to support only valid ASCII 7b input, then that is enough to have all that +13 arithmetic correct.
Also I'm not sure why you do 32 + (i - 126);, that's asking r to convert to ! (33), skipping space (32), which is printable ASCII character.
So after those fixes applied, and simplifying the code a bit (toward C++ style), I ended with:
void encrypt(const string & password)
{
for (unsigned char charToRot13 : password) {
charToRot13 += 13;
if (127 <= charToRot13) charToRot13 -= (127 - ' ');
cout << charToRot13;
}
}
Which does input+output ('r' now maps to ' '):
Please enter your password.
abcopqrstuvw
nop|}~ !"#$%
BUT. The main ROT13 feature is, that you can encrypt and decrypt the text by the same operation. I.e. "abc" -> "nop" -> "abc" -> "nop" -> ...
Your conversion to whole ASCII range breaks that feature. So what you probably want is to cover whole +32 .. +126 range of ASCII values, that's 95 of them. 95/2 = 47.5, not good. Let's remove space, because you already did that by that -126, so you probably don't want it. The value range to encrypt is then +33 .. +126 = 94 of them. 94/2 = 47, good. To get ROT13-like encryption for whole ASCII range (except space) you can use ROT47.
void encrypt(const string & password)
{
for (unsigned char charToRot47 : password) {
if (charToRot47 < 33 || 126 < charToRot47) {
cout << "\nERROR: detected invalid character.\n";
break;
}
charToRot47 += 47;
if (126 < charToRot47) charToRot47 -= 94;
cout << charToRot47;
}
}
This will output:
Please enter your password.
xyz{|}~!"#$%000000IJKLMNOPQRST
IJKLMNOPQRST______xyz{|}~!"#$%
(notice how for example 'y' -> 'J' -> 'y' -> 'J' -> ...)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
As I am new to coding c++ and am taking a object oriented class, I need some help. For this code I want to encrypt it by shifting all of the text that is enter by 1 ascii digit i.e. a -> b, b-> etc. I am suppose to use all ascii values 32 - 126 but I cant figure out why when i try to encrypt anything I only get a "^" as a output.
#include <iostream>
#include <string>
using namespace std;
void encrypt (string &encrypt)
{
string encryption;
for (int i = 0; i < encrypt.length(); i++)
{
encrypt[i]++;
if (i > 126){
encrypt = i - 94;
}
else if (i < 32){
encrypt = i + 94;
}
}
}
void decrypt (string decrypt)
{
string decryption;
for ( int i = 0; i < decryption.length(); i ++)
{
decryption[i]--;
if (i > 126){
decrypt = i + 94;
}
else if (i < 32){
decrypt = i - 94;
}
}
}
int main ()
{
string option;
string encryption1;
string decryption1;
cout << "Do you want to encrypt or decrypt? \n";
cin >> option;
if (option == "encrypt")
{
cout << "What do you want to encrypt \n";
cin.ignore();
cin.clear();
getline (cin, encryption1);
encrypt ( encryption1);
cout << encryption1 << " " << endl;
}
if (option == "decrypt")
{
cout << "What do you want to decrypt \n";
cin.ignore();
cin.clear();
getline (cin, decryption1);
encrypt ( decryption1);
cout << decryption1 << " " << endl;
}
return 0;**
I did something similar to this in my level one programming class last year. We created a Vigenere Cipher that is based off of the architecture of the Cesar cipher.
Something that is useful is to first create a 0 base, i.e. if you are working with values a through b, subtract a from each of the characters that you are encoding first, do the math, double check that the value falls within the range of values (32 through 126 == 0 through 94) and then return the char + a. This would mean rewriting your logic and function to take a char instead of the entire string at once.
As for why you are getting '^' as your only output, the ACSII code for '^' is 94 and your code:
for ( int i = 0; i < decryption.length(); i ++)
{
decryption[i]--;
if (i > 126){
decrypt = i + 94;
}
else if (i < 32){
decrypt = i - 94;
}
}
}
is setting the entire string to char 94. You set i = 0 then say that if i is less than 32 then the string decrypt is equal to the char 0 + 94 which is equal to 94 which is equal to '^'
I need to process a user input to see if it is a palindrome. Our professor said to use cin.ignore() to ignore spaces, numbers, and other characters so we will just compare the letter inputs.
So far I have just found code that ignores just one of these at a time and the code is more advanced than my learning so I do not know how to modify or apply it to my code.
I have the code to check the palindrome, I just do not know how to make it ignore the unwanted inputs.
Sorry this sort of question has been asked many times over but I cannot seem to figure it out.
Thanks in advance.
do
{
checkInput = false;
cout << "Enter the Palindrome: ";
getline(cin, input);
len = input.length();
if (len == 0)
{
cout << "\nNo data was entered, please enter a palindrome.\n";
checkInput = false;
}
} while (checkInput);
for (int i = 0, j = input.size() - 1; i < input.size(); i++, j--)
{
if (input[i] != input[j] && input[i] + 32 != input[j] && input[i] - 32 != input[j])
{
isPalindrome = false;
break;
}
}
if (isPalindrome)
{
cout << "This is a Palindrome!!" << endl;
}
else
{
cout << "This is not a Palindrome." << endl;
}
im assuming that input is a string. if so then what we want to do before your for loop is have another for loop to run through the string and remove anything unwanted from the string. I am going to assume that all you want to deal with are the upper and lowercase letters, as we are focusing on the ascii values between 65-90 and 97-122. source http://www.ascii-code.com/
to so do we can simply check each index in the string to see if it falls between these two ranges, and if it doesn't, then delete it.
for(unsigned int i = 0; i<input.size();i++)
{
if(input[i]< 65 || (90 <input[i] && input[i] < 97) || input[i] > 122)
{
input.erase(i,1);
i--
}
}
that should work.
I'm doing a problem where it asks to input an account number, which consists only of four digits. This has to be accomplished with basic beginner C++.
I need to figure out a way to restrict the input of the integer to four digits. A user should be able to put in 0043 or 9023 or 0001 and it should be an acceptable value....
I think I know how to accomplish it with a string.... getline(cin,input) and then check if input.length()==4?
But I've no idea how I would even do this with an integer input.
Note that if 0043 is intended to be distinct from 43, then the input is not in fact a number, but a digit string, just like a telephone "number".
Read the line as a string input.
Check that the length of input is 4.
Check that each character in the string is <= '9' and >= '0'.
Something like:
std::string read4DigitStringFromConsole()
{
bool ok = false;
std::string result;
while (!ok)
{
std::cin >> result;
if (result.length() == 4)
{
bool allDigits = true;
for(unsigned index = 0; index < 4; ++index)
{
allDigits = allDigits && (
(result[index] >= '0') &&
(result[index] <='9')
);
}
ok = allDigits;
}
}
return result;
}
Something like this should work. Once the user enters something with exactly four characters you can validate it. The rest of the logic is up to you.
#include <iostream>
#include <string>
int main() {
std::cout << "Enter a PIN Number: ";
std::string pinStr;
while(std::getline(std::cin,pinStr) && pinStr.size() != 4) {
std::cout << "Please enter a valid value\n";
}
}
Should you want to store it in an integer form, holding the integers in an std::vector might be beneficial. You can do this easily (loop unrolling was for clarity):
#include <iostream>
#include <string>
#include <vector>
int main() {
std::cout << "Enter a PIN Number: ";
std::string pinStr;
while(std::getline(std::cin,pinStr) && pinStr.size() != 4 ) {
std::cout << "Please enter a valid value\n";
}
std::vector<int> pin;
pin[0] = pinStr[0] - '0';
pin[1] = pinStr[1] - '0';
pin[2] = pinStr[2] - '0';
pin[3] = pinStr[3] - '0';
//pin now holds the integer value.
for(auto& i : pin)
std::cout << i << ' ';
}
You can see it running here
I like your idea to use a string as the input. This makes sense because an account "number" is simply an identifier. You don't use it in calculations. By if (sizeof(input)==4) I think you are trying to check the length of the string. The correct way to do this is if (input.length() == 4). This will check that the user inputs 4 characters. Now you need to make sure that each of the characters is also a digit. You can do this easily by taking advantage of the fact that the ASCII codes for digit characters are ordered as you expect. So if (input[i] >= '0' && input[i] <= '9') will do the trick with an appropriate for loop for the index i. Also, you probably need some kind of loop which continues to ask for input until the user enters something which is deemed to be correct.
Edit:
As an alternative to checking that each character is a digit, you can attempt to convert the string to an int with int value = atoi(input.c_str());. Then you can easily check if the int is a four-or-less-digit number.
// generic solution
int numDigits(int number)
{
int digits = 0;
if (number < 0) digits = 1; // remove this line if '-' counts as a digit
while (number) {
number /= 10;
digits++;
}
return digits;
}
similar to this post.
Then you can call this function to check if the input is 4 digits.
You probably want your code to be responsive to the user input, so I would suggest getting each character at a time instead of reading a string:
std::string fourDigits;
char currentDigit;
std::cout << "Enter 4 digits\n";
for(int i = 0; i < 4; ++i)
{
currentDigit = getch();
if(isdigit(currentDigit))
{
fourDigits += currentDigit;
std::cout << currentDigit; // getch won't display the input, if it was a PIN you could simply std::cout << "*";
}
else
{
// Here we reset the whole thing and let the user know he entered an invalid value
i = 0;
fourDigits = "";
std::cout << "Please enter only numeric values, enter 4 digits\n";
}
}
std::cout << "\nThe four digits: " << fourDigits.c_str();
This way you can handle gracefully invalid character instantly. When using strings, the input will only be validated once the user hits Enter.
So I was going over how I can use an integer type to get the input, and looked at char... since it's technically the smallest integer type, it can be used to get the code... I was able to come up with this, but it's definitely not refined yet (and I'm not sure if it can be):
int main() {
int count=0;
while(!(count==4)){
char digit;
cin.get(digit);
count++;
}
return 0;
}
So, the loop keeps going until 4 characters are collected. Well, in theory it should. But it doesn't work. It'll stop at 2 digits, 5 digits, etc.... I think it could be the nature of cin.get() grabbing white space, not sure.