How to reset .get() - c++

I'm trying to find the amount of letters of the alphabet from a file I have. I can get the first letter A to give me the correct number, but when the for loop goes through it only gives me 0 for the rest of the letters. I feel like it has to do with my .get() not starting at the beginning of the file again. What do I need to do to fix this? Thanks!
ifstream openFile("data.txt");
int numberOfLetters(0);
char letter;
for (int i = 0; i < 26; i++)
{
numberOfLetters = 0;
openFile.clear();
while (!openFile.eof())
{
openFile.get(letter);
if (letter == char(i + 97) || letter == char(i + 65))
{
numberOfLetters++;
}
}
cout << numberOfLetters;
}

The problem is your outer loop: It looks like you want to use this loop to check if the characters taken from the file are equal to certain characters from a certain range. If this is the case, performing the input within the loop is not the way to go.
On the first iteration of the loop, the file will be read completely such that by the second iteration openFile.get(letter) won't extract anything into letter, leaving it with its previous value, same for the rest of the outer iterations. It must be that the last value previous had didn't pass the if() statement test, so numberOfLetter didn't increment.
The solution is to change the way you check if the character is alphabetic. Characters are represented using the ASCII format, which are just integers mapped to characters. Since characters are really integers, you can use arithmetic operations on them. Moreover, characters are represented alphabetically in ASCII, so you can simply compare their values to see if they are in the range of alphabetic characters:
while (openFile.get(letter))
{
if (('a' <= letter && letter <= 'z') || ('A' <= letter && letter <= 'Z'))
{
numberOfLetters++;
}
}
cout << numberOfLetters;
Fortunately the standard library provides a function std::isalpha() that does this for you.
...
if (std::isalpha(letter))
{
numberOfLeters++;
}
...
Based on your comment, checking if a character is alphabetic is not enough. Instead, use a data structure like std::map in order to keep a total count of the number of certain characters:
#include <map>
std:map<char, std::size_t> alpha_count;
while (openFile.get(letter))
{
if (std::isalpha(letter))
alpha_count[letter]++;
}
Now to print how many specific characters there are, loop through the map and print the character's count():
for (auto&& c : alpha_count)
{
std::cout << "# of " << c << ": " << alpha_count.count(c) << '\n';
}

Related

I am trying to use strings inside an array and then splitting that string into its characters

Consider:
std::string words[Maxword] = { "Hello", "World", "Shift", "Green" , "Seven" };
srand(time(NULL));
int iSecret = rand() % 4 + 1;
std::cout << words[iSecret];
I have this code which has an array with words in it. Then it picks a random number and that correlates to a word. How then would I split that word into the letters?
Similar to world, it would be later compared to a letter that the user would guess.
Note sure what you are asking but you can do this to access a character in a string
std::string s = "Word";
std::cout << s[1]; // == 'o'
you can loop
for(int i = 0; i << s.length(); i++){
std::cout << s[i];
}
for(char c : words[iSecret])
cout<<"\t"<< c;
You have a couple of options. Both can be handled in the same manner. With your array of std::string, to split the selected word into characters (in a manner where you can provide a second random index and retrieve that character), you could do:
std::cout << words[iSecret] << "\n\n";
for (size_t i = 0; i < words[iSecret].length(); i++) {
std::cout << "words[iSecret][" << i << "]: '" <<
(char)words[iSecret][i] << "'\n";
}
Above, since words[iSecret] is type std::string, you can use the [ ] index operator to select any character at a valid index within words[iSecret]. For all ways of accessing individual characters, you can see std::basic_string.
If you did not need individual character access by index and simply wanted to loop over each character, you could use a range-based for loop, e.g.
for (const auto& c : words[iSecret])
std::cout << (char)c << '\n';
Example Use/Output
Where running the program with the index operator [ ] for access as shown above, it would produce:
$ ./bin/splitwords-char
Green
words[iSecret][0]: 'G'
words[iSecret][1]: 'r'
words[iSecret][2]: 'e'
words[iSecret][3]: 'e'
words[iSecret][4]: 'n'
or
$ ./bin/splitwords-char
Seven
words[iSecret][0]: 'S'
words[iSecret][1]: 'e'
words[iSecret][2]: 'v'
words[iSecret][3]: 'e'
words[iSecret][4]: 'n'
std::vector As Alternative to array-of-std::string
If you have control over the type for words, then making it std::vector<std::string> words {...} avoids the inflexible limitation of the array-of-std::string. How you access each character would be exactly the same. Whether an element of std::vector<> or an element of the array, the type of the object you are dealing with is still std::string.
In addition to the index operator [ ], you can also use the member function .at() (e.g. words[iSecret].at(i) with the benefit that .at(i) also provides bounds checking on the index provided. See std::basic_string::at
Precedence Problem
You have an error in your use of rand(). % (modulo) has a higher precedence than +, so you never access "Hello" (you only access elements 1 to 4). See C++ Operator Precedence. To correct the problem either enclose (4 + 1) in parenthesis, or simply use rand() % Maxword. That way the values will range from 0 to 4 allowing access to all indexes in words[].

How to read spaces, words, and letters line-by-line from a file in a function using Loops (C++)

so I am having a problem with getting my program to increment values properly.
My program needs to take a file in main(), and then pass that to a function-set to print that is called in main.
The key thing is that I need to use loops within the functions to get Letter Count, Space-Count, and Word Count.
I have the output configured right
cout << line_number << ": " << line << " [" << letter_count << " letters, " << space_count << " spaces, " << word_count << " words]" << endl;
Which results for example
0: Words go here. [# letters, # spaces, # words.]
But with my current functions for Letters and spaces, it doesn't work.
My non-space function for example
int count_non_space(string line) {
int non_space = 0;
for (int i = 0; i < line.length(); i++) {
if (line.c_str() != " ") {
non_space++;
}
}
return non_space;
It counts all of the characters in the line instead and the counterpart (space_count) counts nothing.
And that's not to mention that I don't know how to count the words in the line.
Any advice as to what is going on? as I am certain that count_space and count_non_space should be inverses of each other (count_space being the same function but with == instead of !=)
EDIT: Got the Letter and Space count correct.
Now, how would I get the word count from that sort of method?
EDIT 2: Okay so letter count is off.
It is counting puncutation-characters (commas, periods, dashes, hiphons.etc) as leters.
I have managed to redact periods, dashes.etc from the code manually with a reduction if statement in the count_non_characters function.
But I can't add ' to it as it already uses '' to catch the char comparison
Is there catch-all term for punctuation characters in C++ that I can use for
if (line[i] == "Puncutation") {
non_space--;
}
?
As UnholySheep said, when you compare a c string (char *) you can't use standard logical operators. You will need to use strcmp(). However, if you use a c++ std::string then you can use compare() or logical operators.
As for finding words in a string. Here are a few resources.
c++ counting how many words in line
C++ function to count all the words in a string
C++ Program to find number of Digits and White Spaces in a String
Count words in a given string
For further help. Google: "Get word count per line c++"
Reminder, these two are different data types and have different library support:
std::string myStr
myStr.c_str()
If the goal is to count characters in a string that are not spaces, then there is a way to do this using the STL and lambdas that is much cleaner than writing a bunch of loops and worrying about updating variables.
int count_non_space(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch != ' ';
});
}
This also makes is very straightforward to accommodate for things like spaces and tabs.
int count_non_space(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch != ' ' && ch != '\t';
});
}
To count the opposite (just the spaces) we simply need to change the condition in the lambda.
int space_count(std::string line) {
return std::count_if(line.begin(), line.end(),
[](auto ch) {
return ch == ' ' || ch == '\t';
});
}
As Remy Lebeau helpfully points out, we don't even have to write the lambda. We can simply use the std::isspace function directly instead of the lambda.
int space_count(std::string line) {
return std::count_if(line.begin(), line.end(), std::isspace);
}
Documentation on std::count_if.
Here's how I would revise the function you gave:
int count_non_space(string line) {
int non_space = 0;
for (int i = 0; i < line.length(); i++) {
if (line[i] != ' ') {
non_space++;
}
}
return non_space;
}
Notes:
I changed line.c_str() to line[i] in order to access the ith character of line
I changed " " to ' ' so that it's comparing against the space char, not a string which only contains the space. The comparison would fail if we were comparing the ith char to a string
As for this:
And that's not to mention that I don't know how to count the words in the line.
I don't know how your requirements define a word, but if we assume a word is any contiguous clump of non-space characters, you could use this logic:
initialize bool in_word to false
initialize int word_count to 0
for each char in the string:
if in_word is false and the current char is not a space, then set in_word to be true and increase word_count by 1
if in_word is true and the current char is a space, then set in_word to be false
return word_count

Calculate occurance of each character in a string without using count in C++

Here is my code:
#include <iostream>
#include <string>
using namespace std;
void calc(string s){
for(int i = 0;i < s.size();++i){
int count = 1;
for(int j = i + 1;j <s.size();++j){
if(s[i] == s[j]){
count += 1;
}
}
cout << s[i] <<"(" << count << ")" << " ";
}
}
int main(){
string str;
while(cin >> str){
calc(str);
}
}
Everything works fine, except that I want to iterate through unique characters in string and I don't know how to implement this.
Can you help me with it?
There are many ways you can do this. Here are a few suggestions:
Modify the code you have written so that before you count up how many times a character appears after the current character, you first scan over the characters before you in the string to see if any of them match. If so, skip the current character.
Every time you find a character that matches the current character, replace it with a copy of the first character in the string. Then, whenever you visit a character in the string that isn't in the first position, check if it matches the first character in the string. If so, you've already scanned it. If not, count up its occurrences.
Maintain an auxiliary data structure (an array, a hash table, etc.) mapping characters to their frequencies. Fill in the table by doing one pass over the original string, then iterate over the table, which has unique keys, to print everything out.
Sort the string. Counting how many times each character occurs then boils down to finding the length of each consecutive run of characters in the string.
Option (1) is good if you can't modify the original string and if you're not allowed to use other data structures. Option (2) has excellent time and space requirements if you're allowed to modify the original string. Option (3) is likely the easiest to code up, but uses a bit more space than other approaches. Option (4) is also very easy to code up and, if you use something like heapsort, has good memory usage but is still asymptotically slower than option (2).
Why don't you maintain an auxillary array of 26 length, initialize it to 0 and then increment the corresponding index's value by 1 everytime you encounter a character?
Pseudocode:
auxArray[26] = [0] // 26 length array initialized to zero
for character in string: // loop through every character in the string
auxArray[character - 'a']++; //increment the corresponding index value by 1
print auxArray //print the entire array. [0] will give you count of 'a', and [25] will give you count of 'z'
This is assuming that you have a character String from 'a' to 'z' (All lower case).
In the case where we have an uppercase-lowercase mixture of characters as well, you might similar stuff but instead use an array of 128. In this case, you won't have to subtract 'a' as it was being done to accommodate the indexes with the chars.
auxArray[128] = [0]
for character in string:
auxArray[character]++;
for index in auxArray:
print(((char)index) + " Count is " + auxArray[index])
Another way to do this is with std::map:
std::map<char,int> count;
for (int i = 0; i < s.size(); ++i)
count[s[i]]++;
for (auto iter = s.begin(); iter != s.end(); ++iter)
std::cout << iter->first << ā€œ: ā€œ << iter->second << ā€˜\nā€™;
Not tested, sorry.

Have 2 questions regarding my decryption program, something is off C++

so there's something in my program that is not going the way I feel like it should go. If I could get some help I would appreciate it. I'll explain how it's supposed to work first and follow up with my questions starting with the most important one since I'm stuck on it and it isn't allowing me to progress.
So I wrote an encryption program that asks the user to input a string and then it encrypts it and creates a file called "secret.dat" and puts the encrypted phrase in there.
If the user were to put in the phrase:
hello world 123
it would send this into the file:
11spwwzshzcwoh234&6#12
The "11" indicates how many letters the letter was shifted to the right by. This is followed by the phrase he entered in encrypted. The '&' character shows where the encryption ends. Each space in his phrase uses the previous letter and shifts it over by 4 and finally after the '&' character it tells the number location of where the spaces are seperated by a '#' character.
The current program I am writing decrypts the "secret.dat" file and shows his phrase on the screen.
This is what I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
//Declare Variables
int shift;
ifstream inData;
string input;
string output;
int length;
//Open file
inData.open("secret.dat");
//Begin program
inData >> shift;
getline(inData, input, '&');
length = input.length();
for (int count = 0; count < length; count++)
{
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' - shift) % 26) + 'a';
}
else if (input[count] >= '0' && input[count] <= '9')
{
output += ((input[count] - '0' - shift) % 10) + '0';
}
}
//Declare variables for location of spaces
int i = 0;
char ignore;
int spaces[20];
int location;
//Begin finding the spaces
while (!EOF)
{
inData >> location;
spaces[i] = location;
inData >> ignore;
}
//Preview each result to compare and make sure they are working right
cout << shift << endl;
cout << input << endl;
cout << output << endl;
cout << spaces[0] << endl;
cout << spaces[1] << endl;
return 0;
}
This is what I get as a result
11
spwwzshzswoh234
helloh]oXld]'()
4704512
0
Obviously the last 3 lines are not working correctly (NOTE: this is not how I am going to display it, I just printed these to the screen so that I could see what the result was and make sure it was correct, which it isn't).
So, my first and most important question is why my while loop isn't working correctly. It gives me a bunch of random numbers in the first array slot when it should put a 6 in the first spot, then it should skip the next character and then put a 12 in the second spot in the array which it just puts a 0 there. If I just call an integer from the file outside of the while loop it gives me a 6 no problem so I'm unsure on why it is doing this. I figured it would put the first integer in the first slot in the array, then skip the next character, then put the next integer in the array and skip the next character and so on until the end of the file. This part is what's keeping me from proceeding in the program so I put this as the most important.
Second, what's wrong with my formula for shifting the characters back? I used this same exact formula for shifting the characters forward for my encryption program except I added shift so I assumed just subtracting the shift would decrypt it.
Thanks for anyone willing to help!
In your encryption scheme, the character 'h' stands for the letter 'w' in clear text.
Let's work through how your code tries to decode this:
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' - shift) % 26) + 'a';
}
input[count] is character "h". 'h' - 'a' is 7. Your value of "shift" is 11.
Your expression calculates (7-11) % 26, or -4 % 26.
Pop quiz: what's -4 % 26? You'd be surprised to learn that the answer is -4. Adding -4 to 'a' produces the character ']', which is what you see, in the corresponding position, in your output.
To fix this, change this line to read:
output += ((input[count] - 'a' - shift + 26) % 26) + 'a';
And change the other line, for digits, in the same way.

C++ for loop with char type

>The character 'b' is char('a'+1),'c' is char('a'+2),etc. Use a loop to write out a table of characters with their corresponding integer values.
I cannot finish this exercise because of this error.
error: lvalue required as increment operand
for(char a='a'; a<24; ++a)
{
cout<<char('a'++);
}
The loop body will never execute with the controlling expression a < 24 because you have initialized variable a with character a and all printable characters are not less than ASCII value 32.
Try this:
for(char a='a'; a < 'a' + 24; ++a)
{
cout << a;
}
I think you would be less confused if you named your variable letter instead of a, because it only represents the letter 'a' at the very beginning.
for(char letter='a'; letter<24; ++letter)
{
cout<<char('a'++);
}
I'm going to assume you actually want to print out the entire alphabet, not just the first 24 letters.
It looks from here like you tried to do a mix of two possible approaches. In the first approach, you increment a char from a to z with each iteration of the for loop and print it out each time. In the second approach, you increment some offset from 0 to 25 and print out 'a' + offset.
You mix these two approaches up in the first line. You're starting the loop with letter set to 'a', which you do not know the numerical value of. You then compare letter to see if it is less than 24. Well in any ASCII-compatible character set, the character 'a' has value 97, so this condition will never pass.
You then misuse ++ on the cout line. The ++ operator attempts to modify its operand, yet 'a' is a literal and so cannot be modified. Have a look at what your assignment told you. You can do 'a' + 1 to get 'b', for example, so this assumes you have an offset (which you don't with your current approach).
So to repeat, you have two options. First: keep letter as a char starting at 'a' and fix the condition so that it checks if letter is less than or equal to the value of 'z' and then just print out letter. Second: change letter to offset and start it off at 0 and increment it while it is less than 26, and then print out 'a' + offset.
Note, however, that both of these approaches assume that the letters have consecutive values in the execution character set. This is not necessarily true.
The ++ operator is a "hidden assignment" (the operand's value is changed by it). But you can only assign to variables, which 'a' is not.
I know this has been closed for a while but since the exercise was about while loops and not for loops, I thought I would offer my solution. I'm just going through the book myself and someone in the future might stumble over this.
int i = 0;
char n = 'a'; // this will list the alphabet
int conv = 0;
conv = n; // this converts the alphabet into integer
while (i < 26) { // starts from 0 and goes to 25
cout << char(n + i) << '\t' << conv + i << '\n';
++i;
}
You may use the following: (http://ideone.com/akwGhl)
#include <iostream>
int main()
{
for (char c = 'a'; c <= 'z'; ++c) {
std::cout << "letter " << c << " has value " << int(c) << std::endl;
}
return 0;
}
hey through troubleshooting i obtained a sample that worked , i have yet to perfectly understand how my code works but as the solutions that were proposed to me here seemed too technical for my level i figured that i should publish mine
#include"header files . h"//i use the libraries given in the book
int main () {
char a ='a';
int i = 0 ;
while (i <= 25)//for (i = 0 ; i <= 25 ; i++)
//for those who used for
{
cout << a << '\t' << 'a' + i << endl;
a += 1; // augments the character value of a to b ... then to z
i++; // augments the value of i allowing us thus to make the augmentation,if you are using the for structure do not put I in your code
}
}