Changing letters by ascii value - c++

I am trying to use ascii values to check different values of a letter to decipher a simple Cesar cipher. I am running into problems when the program tries to check a letter after z. I am using all lower case so if the letter is on z it should move to the beginning of the alphabet again. My code is as follows
#include <iostream>
using namespace std;
#include <string>
#include <vector>
int main()
{
string unencr;
char temp;
cout << "Enter string:" << endl << endl;
cin >> unencr;
for(int i = 0; i<26; i++){
for(int j = 0; j < unencr.size(); j++){
temp = unencr[j];
if ((int)temp + i <= 122){
temp = (int)temp + i;
}
if ((int)temp + i > 122){
temp = (((int)temp +i) % 122)+96;
}
cout << temp;
}
cout << endl;
}
return 0;
}

Your problem is that in your if statement you say (((int)temp +i) % 122)+96; But what if the char was 155 this would then make it equal to 130. Which is out of the bounds of a-z.
What you want to do instead: if(temp > 122) then you should (temp-122)%122 + 97 instead of moding it by itself.

To change a single character c, use this line:
c = ((c - 'a' + 13) % 26) + 'a';
c - 'a' // convert to position in the alphabet, 0 based
c - 'a' + 13 // rot13 (or any other shift that you want)
(c - 'a' + 13) % 26 // wrap around after 'z'
((c - 'a' + 13) % 26) + 'a' // convert it to ASCII again
Also you might want to embrace all of C++'s features:
#include <iostream>
#include <string>
int main() {
// read a whole line instead of a single word:
std::string str;
std::getline(std::cin, str);
// iterate over the string, not over the letters of the alphabet:
for (char &c : str) {
if (('a' <= c) && (c <= 'z')) {
c = (((c + 13) - 'a') % 26) + 'a';
}
}
std::cout << str << std::endl;
return 0;
}

Related

using isDigit to find charecters c++

Trying to figure how I can use isDigit to ignore every character except x, X, e, E within a string. As you can see below I'm doing duodecimal to decimal with x equal to 10 and e equal to 11 (not case sensitive). Having trouble with cin.ignore(). The output should be 36. The string duo should read in the 3 then 0 and negate the rest.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
using namespace std;
main() {
using str_t = std::string::size_type;
str_t idx = 0;
int decValue = 0;
string duo = "30-something";
while (isspace(duo.at(idx)) && idx < duo.length()) {
idx++;
}
for (std::string::size_type i = 0; i < duo.length(); ++i) {
decValue *= 12;
if (isdigit(duo.at(i))) {
decValue += duo.at(i) - '0';
}
else if (duo.at(i) == 'x' || duo.at(i) == 'X') {
decValue += 10;
}
else if (duo.at(i) == 'e' || duo.at(i) == 'E') {
decValue += 11;
}
/// Program works if this executable line is taken out
else if (!char.isDigit(duo.at(i))) {
cin.ignore();
}
}
cout << decValue << endl;
}
Below I modified your code so that it gives correct answer. For input 30-something it gives 36 as output.
As I understood you want to finish conversion right after 30 i.e. ignore -something. For such behaviour I put a flag stop_on_first_non_digit in my code, if it is true then it finishes on first non-digit character. But you may set it to false then I just skip non-digit chars but use all chars that are digits, for example -something has e in it, so contains one digit, if stop_on_first_non_digit is false then this single e digit will be used. By default now it is true so that it behaves the way you like.
Also I kept your logic of skipping first spaces in a string so you can input 30-something (leading spaces) and it gives 36 too.
Try it online!
#include <string>
#include <cctype>
#include <iostream>
int main() {
std::string duo = "30-something";
bool stop_on_first_non_digit = true;
size_t i = 0;
int decValue = 0;
while (i < duo.length() && std::isspace(duo.at(i)))
++i;
for (; i < duo.length(); ++i) {
char c = duo.at(i);
int digit = 0;
if (std::isdigit(c))
digit = c - '0';
else if (c == 'x' || c == 'X')
digit = 10;
else if (c == 'e' || c == 'E')
digit = 11;
else {
if (stop_on_first_non_digit)
break;
else
continue;
}
decValue *= 12;
decValue += digit;
}
std::cout << decValue << std::endl;
}
Output:
36

Why does the program print 0 instead of the average?

Wrote a function that calculates the average length of words in a sentence.
Why does the program print 0 instead of the average?
Please help me fix my mistake.
If you know how to make an implementation in one function, please write.
#include <iostream>
#include <string>
using namespace std;
int CountWordsAndLetters(char* str, int& words, int& letters)
{
words = 0;
int i = 0;
letters = 0;
while (str[i] == ' ')
i++;
for (; str[i]; i++) {
if (((str[i] >= 'a') && (str[i] <= 'z'))
|| ((str[i] >= 'A') && (str[i] <= 'Z')))
letters++;
if (str[i] == ' ') {
words++;
while (1)
if (str[i] == ' ')
i++;
else {
i--;
break;
}
}
}
words = words + 1;
return (words);
}
float AverageLetters(float words, float letters)
{
float a = (double)(letters / words);
return a;
}
int main()
{
char array[255];
int words = 0;
int letters = 0;
cout << "Enter the string\n\n";
gets_s(array);
int size;
for (size = 0; array[size]; size++)
;
char* str = new char[size];
CountWordsAndLetters(str, words, letters);
cout << "\nAverage number of letters per word: "
<< AverageLetters(words, letters);
return 0;
}
If you know how to make an implementation in one function, please write.
Here, you are allocating an uninitialized array of char:
char* str = new char[size];
You put nothing in it.
You then pass it to CountWordsAndLetters:
// here -------v
CountWordsAndLetters(str, words, letters);
You should consider simply sending array instead:
CountWordsAndLetters(array, words, letters);
Here's a live example of your code working.

Looping back to the beginning of the alphabet after z

I am working on a problem for school, and I have to write a program that rotates 13 characters. I have the program done, but it rotates into some weird characters. I want to make it look back to 'a' after it reaches 'z' for both uppercase and lowercase. Basically, I want to restrict my options to A-Z and a-z.
Tried a mixture of while statements and if statements, and ended up on with just some if statements. I know they are wrong, but it runs in its current state.
#include <iostream>
using namespace std;
//Function Prototypes
char rot(char c);
int mylen(char c[]);
int main()
{
char in[120], out[120];
int i; // index into in
cout << "Enter text: ";
cin.getline(in,120);
while (strcmp(in, "exit"))
{
for (i = 0; i < mylen(in); i++)
{
out[i] = rot(in[i]);
}
out[i++] = '\0';
cout << out << endl;
cout << endl << "Enter some more text: ";
cin.getline(in,120);
}
return 0;
}
char rot(char c)
{
if (c >= 'a' and c <= 'z')
c = c + 13;
if (c > 'z')
c = c - 26;
else if (c >= 'A' and c <= 'Z')
c = c + 13;
if (c > 'Z')
c = c - 26;
return c;
}
int mylen(char c[])
{
int cnt = 0;
while (c[cnt] != '\0')
cnt++;
return cnt;
}
I am looking just to have it rotate 13 characters, and when someone inputs rotated code, to rotate it again 13 characters.
I suggest you should carefully observe the table of ASCII code to display the character.There are 6 characters between the uppercase letter "A"~"Z" and the lowercase letter "a"~"z"
Here is my code:
if (c >= 'n' && c <= 'z')
{
c = c - 13;
}
else if (c >= 'a' && c <= 'm')
{
c = c + 13;
}
if (c >= 'N' && c<='Z')
{
c = c - 13;
}
else if (c >= 'A' && c <= 'M')
{
c = c+13;
}

C++ Reading characters from file, count each one and sort

I need help completing a task for class, basically I need to read letters from a text file, count each letters occurrence and sort them by most occurrences. I'm having a problem remembering each letters original count after sort (since index changes)
The problem is that the result letters are appearing more then once so I lose some of the letters
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main ()
{
char letter, b[26] = {};
int number[26] = {0}, temp, i, j;
ofstream outfile ("test.txt");
srand (time(NULL));
for(int i=0;i<20;i++){
char c = rand() % 26 + 65 + rand() % 2 * 32;
outfile <<c<<endl;
}
outfile.close();
ifstream file( "test.txt");
while(file >> letter){
if (letter >= 'a' && letter <= 'z') number[letter - 'a']++;
if (letter >= 'A' && letter <= 'Z') number[letter - 'A']++;
}
for(i=0; i<26; i++)
{
for(j=i+1; j<26; j++)
{
if(number[j] > number[i])
{
temp = number[i];
b[i] = char(97+j);
number[i] = number[j];
number[j] = temp;
}
}
}
for(i=0;i<26;i++){
if(number[i] != 0)cout<<b[i]<<" "<<number[i]<<endl;
}
return 0;
}
l 3
m 3
m 2
q 2
w 2
j 1
l 1
m 1
o 1
q 1
t 1
v 1
w 1
To broaden what i was saying in comments about using a struct, consider this:
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
struct CharInstance {
int count;
char letter;
};
int main()
{
char letter;
int i, j;
CharInstance temp;
CharInstance charInst[26] = { 0 };
// create test data randomly
{
ofstream outfile("test.txt");
srand(time(NULL));
for (int i = 0; i < 500; i++) {
char c = rand() % 26 + 65 + rand() % 2 * 32;
outfile << c << endl;
}
outfile.close();
}
// read in data and store in array
{
ifstream file("test.txt");
while (file >> letter) {
// force lowercase to uppercase so we count both lowercase and uppercase as the same
if (letter >= 'a' && letter <= 'z') letter -= 32;
// since all input is now uppercase, ignore anything that isn't in uppercase range
if (letter < 'A' || letter > 'Z') continue; // skip non-alpha chars
const int ind = letter - 'A';
++charInst[ind].count;
charInst[ind].letter = letter;
}
file.close();
}
// bubble sort
for (i = 0; i < 26; i++)
{
for (j = i + 1; j < 26; j++)
{
if (charInst[j].count > charInst[i].count)
{
temp = charInst[i];
charInst[i] = charInst[j];
charInst[j] = temp;
}
}
}
for (i = 0; i < 26; i++) {
cout << charInst[i].letter << ": " << charInst[i].count << " " << endl;
}
return 0;
}
If you don't mind C++11.
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
int main() {
std::ifstream in("sort.cpp");
// Map to store counts of each character.
// Note: this won't work with some international characters (i.e. Chinese).
std::map<char, int> histogram;
char ch = 0;
while (in.get(ch)) {
// TODO
// Filter out characters you don't want, as this would also pick whitespaces
// and newlines.
// Increment the count for |ch|.
// This would create new map element if the count was zero.
++histogram[ch];
}
// Move map contents into an array of pairs character->count.
std::vector<std::pair<char, int>> pairs(histogram.begin(), histogram.end());
// Sort the array. The third parameter is a function used as a custom comparator.
std::sort(pairs.begin(), pairs.end(),
[](const std::pair<char, int>& left, const std::pair<char, int>& right) {
// Use the count to compare |left| and |right|.
return left.second > right.second;
});
for (const auto& pair : pairs) {
std::cout << pair.first << " " << pair.second << std::endl;
}
}
g++ -std=c++11 sort.cpp
./a.out
207
t 79
a 62
e 61
r 61
i 53
s 51
o 50
n 50
c 46
...

How can I correctly encrypt the input when there is a space?

#include <iostream>
#include <cstring>
#include <string>
//#include <cctype>
using namespace std;
string k;
int key[1024];
int size = 0;
int count = 0;
char text[1024];
char o;
void encrypt(char input[]);
void decrypt(char input[]);
// get arguments from command line
int main(int argc, char *argv[])
{
if(argc >= 3)
{
k = argv[2];
// removing spaces from key
// storing key into char array
for(int i = 0; i < k.length(); i++)
{
if(k.at(i) == ' ')
{
key[i] = k.at(i+1);
i++;
}
else
{
key[i] = k.at(i);
// cout << key[i] << endl;
}
size++;
}
if(strcmp(argv[1], "-e") == 0)
{
// get text from user
// encrypt
cout << "encryption " << endl;
cin.getline(text, sizeof(text));
encrypt(text);
}
else if(strcmp(argv[1], "-d") == 0)
{
// get text from user
// decrypt
cout << "decryption " << endl;
decrypt(text);
}
}
}
void encrypt(char input[])
{
string word = input;
char wkey[word.length()];
// cout << word.length();
for(int i = 0; i < word.length(); count++, i++)
{
// if input is larger than the key
// chars of key will repeat until the size is the length of the input
if(i > size - 1)
{
if(i == size)
{
count = 0;
}
wkey[i] = wkey[count];
}
else
{
wkey[i] = key[i];
}
// if input is a space, cout a space
if(input[i] == ' ')
{
cout << " ";
}
// if input is something other than a letter, then just print it out
else if(input[i] < 65 || input[i] > 122 || input[i] > 90 && input[i] < 97)
{
cout << input[i];
}
else
{
// ignoring case of the letters in the key
// give the letters a range of 0-25
if(wkey[i] >= 65 && wkey[i] <= 90)
{
wkey[i]-= 'A';
}
else if(wkey[i] >= 97 && wkey[i] <= 122)
{
wkey[i]-= 'a';
}
// cout << wkey[i] << endl;
// if input is uppercase, put it in the range of 0-25
// make shift by adding to char in key
// mod by 26 to wrap around
// o is the encrypted character that will be printed
if(input[i] >= 65 && input[i] <= 90)
{
o = ((wkey[i] + (input[i] - 'A')) % 26) + 'A';
}
else if(input[i] >= 97 && input[i] <= 122)
{
o = ((wkey[i] + (input[i] - 'a')) % 26) + 'a';
}
}
cout << o;
}
}
The problem is that I am having trouble encrypting plaintext if that text contains a space. If the text is just one single word, then the program works. In the encryption function where I test the input for a space, I just print out a space, and then the next iteration of the for loop occurs. I think that this problem is occurring because once that next iteration occurs, the character in the key that is at the same index as the space in the input is skipped. I've tried doing an if statement to roll back to the skipped letter in the key, but I still get the wrong output. If anyone could give me some advice on how to fix this problem, I would really appreciate it.