Iterations of while loop returns strange values - c++

I have two questions:
Assume the characters entered by the user in input are all contained in alphabet:
If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
using namespace std;
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
int shift = 3, index = 0;
cin >> input;
while(index < input.length()){
if(alphabet.find(input[index]) != NULL){
output += alphabet[(alphabet.find(input[index]) + shift) % 62];
}
index++;
}

If my input starts with "A", the first character in my output is "A", but if I start with any other character in alphabet, the output is the original character shifted to the right by 3. If my input starts with "A", why does my output also start at "A" and not at "D"?
It doesn't. It skips the "A" and does not add it to the output at all!
This is because std::string::find() DOES NOT return a pointer, it returns an index. If it does not find a match, it returns std::string::npos (-1). Comparing NULL to an index treats the NULL as index 0. So, when find() does find "A", it returns 0, which you then compare as equal to NULL (0) and thus skip adding "D" to the output. All of the other input characters make find() return indexes other than 0, so they don't compare equal to NULL and so you shift all of them (including ones that cause find() to return npos, you shift all of those to index 2).
If my input is a string that has spaces (e.g. "Stack Overflow"), why is the first word the only component of my output? (How is the computer interpreting this?) I understand C++ considers new lines, spaces, and tabs to be whitespace, but I thought if the space was in a string, it would be treated as a character. How can I modify my code so the space and the rest of my input is included (preferably shifted) in my output?
operator>> reads whitespace-delimited words. It first skips leading whitespace (unless std::noskipws is used), and then it reads until it encounters whitespace. To read a string with spaces in it, use std::getline() instead.
With that said, try this instead:
using namespace std;
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ##$%^&*()"; //a 62 character string
string input, output;
const int shift = 3;
getline(cin, input);
for (string::size_type index = 0; index < input.length(); ++index) {
string::size_type found_index = alphabet.find(input[index]);
if (found_index != string::npos) {
output += alphabet[(found_index + shift) % alphabet.size()];
}
}
/*
Or, using C++11 or later:
for (char c : input) {
auto found_index = alphabet.find(c);
... (same as above) ...
}
*/
Also, how does one format variables when asking questions on StackOverflow so that they're in little code blocks within writing a question? I see that on other people's posts, but I don't know how to do it, and it makes things far more readable.
Blocks of code can be indented by 4 spaces. The toolbar on StackOverflow's editor has a button for formatting code blocks. Just select the code and press the button.
Code inline of other text can be wrapped in `` quotes.
Click on the ? button on the right side of the editor's toolbar to see the supported formatting markup.

Related

Why is the length of a string off by one on the first read of a file?

I am perplexed with the way my program is performing. I am looping the following process:
1) take the name of a course from an input file
2) output the length of the name of the course
The problem is that the first value is always one less than the actual value of the string.
My first string contains 13 characters (including the colon), but nameOfClass.length() returns 12. The next string, the character count is 16 and indeed, nameOfClass.length() returns 16.
Every value after that also returns the expected value, it is only the first that returns the expected value minus 1.
Here's the (reduced) code:
std::ifstream inf("courseNames.txt");
int numberOfClasses = 10;
string nameOfClass;
for (int i = 0; i < numberOfClasses; i++) {
std::getline(inf, nameOfClass,':');
std::cout << nameOfClass.length() << "\n";
}
The file looks like this (courseNames.txt):
Pre-Calculus:
Public-Speaking:
English I:
Calculus I:
...etc. (6 more classes)
This is what I get:
12
16
10
11
Can anyone explain this behavior of the .length() function?
You have a problem, but you have the wrong conclusion. std::getline reads but doesn't output the delimiter, and so the first result is indeed 12.
It also doesn't output the delimiter for any subsequent lines, so why is there always one more? Well, look what is after that :. That's right, a new line!
Pre-Calculus:
^ a new line
So your nameOfClass variable, except for the first string, always stores an extra newline before the other characters.
The fix is easy enough, just ignore the newline after reading the string.
inf.ignore(); // ignore one character
So, not the first result was wrong, it was the only one right :)

Shift cipher in C++ (How to get ASCII value and handling numbers)

I have a program set up already to read in a file and split each line into words, storing them into a double vector of strings. That is,
std::vector < std::vector <std::string> > words
So, the idea is to use an array from alphabet a-z and using the ASCII values of the letters to get the index and swapping the characters in the strings with the appropriate shifted character. How would I get the value of each character so that I can look it up as an index?
I also want to keep numbers intact, as a shift cipher, I believe, doesn't do anything with numbers in the text to be deciphered. How would I check if the character is an int so I can leave it alone?
If you want the ASCII value, you simply have to cast the value to a int:
int ascii_value = (int)words[i][j][k];
If you want to have a value starting from A or a you can do this:
int letter_value_from_A = (int)(words[i][j][k] - 'A');
int letter_value_from_a = (int)(words[i][j][k] - 'a');
Your char is nothing else than a value. Take this code as example (I am used to program C++11, so this will be a little ugly):
char shiftarray[256] = {0, 0, 0, 0 // Here comes your map //
std::string output;
for(int w=0; w<words.length(); w++)
{
for(int c=0; c<words[w].length(); c++)
{
output.pushback(shiftarry[words[w][c]]);
}
output.push_back(' ');
}
I do not know how to do it in anything other than basic, but very simply get the ascii value of each letter in the string using a loop. As the loop continues add a value to, or subtract a value from the ascii value you just obtained, then convert it back to a letter and append it to a string. This will give you a different character than you had originally. By doing this, you can load and save data that will look like gibberish if anyone tried to view it other than in the program it was written in. The data then becomes a special propriatry document format.

Comparing individual characters in a string. Finding Consonants in a user input string of letters

I've been tasked to write code for a c++ program that will find the consonants in user input. So, if I enter abc, the program will tell me that there are two consonants. The question is below. I'm not looking for someone to write the code for me, I just need someone to help me figure out how to compare user input characters to a string.
Write a program that determines how many consonants are in an entered string of 50 characters or less. Output the entered string and the number of consonants in the string. You can assume the following ;
Consonants: bcdfghjklmnpqrstvwxyz
Define a string with all consonants:
string cons = "bcd" // etc
Put your actual sting to lower case, if needed
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
Next, itearete through your string characters and try to find this character in the consonant string.
int consonants = 0;
for (string::iterator i = str.begin(); i !< str.end(); ++i)
if (cons.find(*i) != string::npos)
++consonants;
Or, if you are sure that your string will only contains characters from a-z, use vowels as suggested below:
string vow = "aei" // etc
//...
int consonants = 0;
for (string::iterator i = str.begin(); i !< str.end(); ++i)
if (vow.find(*i) == string::npos)
++consonants;
This may not be the most efficient method, but since you're only dealing with strings of less than 50 characters, it's not a big deal.
Here's the pseudocode:
Create a string containing all of the consonants as you listed above.
Prompt user for input
Store the input in a string
Use a loop to iterate through each character of the input string
Use another loop to check each character against your string of consonants
If it matches a consonant, increment your counter
Output the input string and count
If you're using C++ strings, you'll use the string length in your loop stopping condition.
If you're using C strings, you'll use the null byte in your loop stopping condition.

getline() Adding Character to Front of String? -- Actually substr syntax error

I'm writing a program that will balance Chemistry Equations; I thought it'd be a good challenge and help reinforce the information I've recently learned.
My program is set up to use getline(cin, std::string) to receive the equation. From there it separates the equation into two halves: a left side and right side by making a substring when it encounters a =.
I'm having issues which only concerns the left side of my string, which is called std::string leftSide. My program then goes into a for loop that iterates over the length of leftSide. The first condition checks to see if the character is uppercase, because chemical formulas are written with the element symbols and a symbol consists of either one upper case letter, or an upper case and one lower case letter. After it checks to see if the current character is uppercase, it checks to see if the next character is lower case; if it's lower case then I create a temporary string, combine leftSide[index] with leftSide[index+1] in the temp string then push the string to my vector.
My problem lies on the first iteration; I've been using CuFe3 = 8 (right side doesn't matter right now) to test it out. The only thing stored in std::string temp is C. I'm not sure why this happening; also, I'm still getting numbers in my final answer and I don't understand why. Some help fixing these two issues, along with an explanation, would be greatly appreciated.
[CODE]
int index = 0;
for (it = leftSide.begin(); it!=leftSide.end(); ++it, index++)
{
bool UPPER_LETTER = isupper(leftSide[index]);
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
if (UPPER_LETTER)// if the character is an uppercase letter
{
if (NEXT_LOWER_LETTER)
{
string temp = leftSide.substr(index, (index+1));//add THIS capital and next lowercase
elementSymbol.push_back(temp); // add temp to vector
temp.clear(); //used to try and fix problem initially
}
else if (UPPER_LETTER && !NEXT_LOWER_LETTER) //used to try and prevent number from getting in
{
string temp = leftSide.substr(index, index);
elementSymbol.push_back(temp);
}
}
else if (isdigit(leftSide[index])) // if it's a number
num++;
}
[EDIT] When I entered in only ASDF, *** ***S ***DF ***F was the output.
string temp = leftSide.substr(index, (index+1));
substr takes the first index and then a length, rather than first and last indices. You want substr(index, 2). Since in your example index is 0 you're doing: substr(index, 1) which creates a string of length 1, which is "C".
string temp = leftSide.substr(index, index);
Since index is 0 this is substr(index, 0), which creates a string of length 0, that is, an empty string.
When you're processing parts of the string with a higher index, such as Fe in "CuFe3" the value you pass in as the length parameter is higher and so you're creating strings that are longer. F is at index 2 and you call substr(index, 3), which creates the string "Fe3".
Also the standard library usually uses half open ranges, so even if substr took two indices (which, again, it doesn't) you would do substr(index, index+2) to get a two character string.
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
You might want to check that index+1 is a valid index. If you don't want to do that manually you might at least switch to using the bounds checked function at() instead of operator[].

How to remove a character from the string and change data if need it?

I have possible inputs 1M 2M .. 11M and 1Y (M and Y stand for months ) and I want to output "somestring1 somestring2.... and somestring12" note M and Y are removed and the last string is changed to 12
Example: input "11M" "hello" output: hello11
input "1Y" "hello" output: hello1
char * (const char * date, const char * somestr)
{
// just need to output final string no need to change the original string
cout<< finalStr<<endl;
}
The second string is getting output as a whole itself. So no change in its output.
The second string would be output as long as M or Y are encountered. As Stack Overflow discourages providing exact source codes, so I can give you some portion of it. There is a condition to be placed which is up to you to figure out.(The second answer gives that as well)
Code would be somewhat like this.
//Code for first string. Just for output.
for (auto i = 0 ; date[i] != '\0' ; ++i)
{
// A condition comes here.
cout << date[i] ;
}
And note that this is considering you just output the string. Otherwise you can create another string and add up the two or concatenate the existing ones.
is this homework? If not, here's what i'd suggest. (i ask about homework because you may have restrictions, not because we're not here to help)
1) do a find on 'M' in your string (using find), insert a '\0' at that position if one is found (btw i'm assuming you have well formatted input)
2) do a find on 'Y'. if one is found, insert a '\0' at that position. then do an atoi() or stringstream conversion on your string to convert to number. multiply by 12.
3) concatenate your string representation of part 1 or part 2 to your somestr
4) output.
This can probably be done in < 10 lines if i could be bothered.
the a.find('M') part and its checks can be conditional operator, then the conversion/concatenation in two or three lines at most.