Mashed-up data in string vector - c++

I've been trying to fix this for ages,
I've got a program that takes in a random word from a supplied dictionary (txt file),
and then adds this word to a vector of strings.
The randomWord() function works as intended, but the getWords() seems to mash-up everything when I try to print out the vector.
The vector declaration:
vector<string> pass_words; //Array of words used in password
These are the two functions:
//gets a random word from the wordlist file.
string randomWord()
{
wordfile.open ("wordlist.txt"); //open the wordlist file
string wordonline;
string word;
int wordwant = rand()%58110; //Maximum is 58109 which is the last word, minimum is 0.
for (int linenum = 0; getline (wordfile, wordonline) && linenum <(wordwant+1) ; linenum++) {
if (linenum == wordwant) {
word = wordonline;
}
}
wordfile.close();
return word;
}
// gets random words based on number of words supplied.
void getWords() {
cout << "WORD GET" << endl;
string thisword;
for (int i=0 ; i<num_words; i++) {
thisword = randomWord();
pass_words.push_back(thisword) ;
cout << pass_words[i] << " " ; //debugging
}
cout << endl; //debugging
return;
}
Here is a sample output
WORD GET
posingdsate
What am I doing wrong?
Also apparently, when I put another loop for the pass_words vector, I can see the values, but never after or within the getWords() function.
Here's the other loop's output:
housemaids
--
necessitate
--
contacts
--
kampala
--
pion
--
scooped
--
posing
--

There is a very high probability that you're reading in CR characters from a CRLF delimited file, assuming it is just LF delimited, and printing them, where the carriage return will slam the cursor to the left and write over existing text.
You will need to either read this as CRLF or strip out any CR or LF characters.
You can also force a newline:
std::cout << pass_words[i] << std::endl;

Related

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

What is a better way to get C++ get text data into a program rather than using fstream

this is a very challenging question as I'm not sure how to ask it correctly.
I wrote a program that will read in the same text data on load every time. The text data is a list of words in the dictionary and the program solves anagram type puzzles (like Jumble, Boggle, Scrabble, etc). This text data never changes. Currently I use to read a text file which MUST be present in the same folder as the .exe that is built. This assumes the user would not just go in and erase, edit, or otherwise corrupt the text file or something really within the realm of possibility for a user to do. Not only that but locking a file and reading it are very noticeably slow operations.
Most of what the program does is convert the .txt file into an abstract data type (ADT) which sorts the word into a 'signature' then builds a set of words that have the same signature. These sets are stored in a structure (called map here) that is a key:value type data structure where the key is the signature. Anyway that info is irrelevant to the question just sufficient to say that on load I need to build my ADT in memory. I'm looking for a more sophisticated way than text files.
Since I'm new at programming there is probably a much better way. I just don't know how to even ask the question since I don't know what is available out there.
I understand databases, but then again it seems like that relies on an external file. I have seen posts which talk about storing data in a .h file but they always want to build a character array (char[i]), which would require converting this data into my ADT and that seems again like a waste of time when the program is loading. (why bother converting it into a char array just to read it back to the ADT?)
/*
* Project: myJumble
* Created by CS106 C++ Assignment Wizard 0.1
*
* Name: Brad Beall
* Section: Life
* This code will solve the jumble puzzles in the newspaper.
*/
#include <fstream>
#include <iostream>
#include "simpio.h"
#include "map.h"
#include "set.h"
#include "genlib.h"
//This function swaps two characters.
void Swap(char &ch1, char &ch2)
{
char tmp = ch1;
ch1 = ch2;
ch2 = tmp;
}
//This function sorts all the chars in a word in alphabetical order
string SortWord(string inWord)
{
inWord = ConvertToLowerCase(inWord);
//these two for loops will sort the string alphabetically
// - idea is starting from the front, find the 'smallest' character in the string.
// (where a is 'smaller' than b)
// then move that smallest character to the front of the string
// now move to the next character and again look for the smallest character.
// Example: for "peach", first move the 'a' to the front to form "apech", then move 'c' to form "acpeh"...
for (int i = 0; i < inWord.length(); i++) {
int minIndex = i;
for (int j = i+1; j < inWord.length(); j++)
{
if (inWord[j] < inWord[minIndex])
{
// looking for the 'smallest' character
minIndex = j;
}
}
Swap(inWord[i], inWord[minIndex]);
}
return inWord;
}
void BuildDictionary(Map<Set<string> > &kDict, ifstream &in)
{
string nextWord = "";
while(true)
{
//read in the next word from the dictionary
in >> nextWord;
if (in.fail()) break;
//sort letters alphabetically using SortWord, use that as the key
// and then add that key:value pair to the set.
kDict[SortWord(nextWord)].add(nextWord);
}
}
//this function prints a set
void PrintSet(Set<string> &inputSet)
{
Set<string>::Iterator it = inputSet.iterator();
while (it.hasNext())
{
cout << it.next() << endl;
}
}
int main ()
{
////debug the function: string SortWord(string inWord)
//cout << "Enter a word to sort" << endl;
//string tempString = GetLine();
//tempString = SortWord(tempString);
//cout << tempString;
//building the dictionary may take some time.
cout << "Loading the dictionary. This may take some time." << endl;
//read in the text file with all dictionary words
ifstream in;
in.open("enable1.txt");
//call the member function that will create our data structure
//this will be a MAP:
// - key: the alphabetized letters from a word, or the word's "signature"
// - value: a Vector of words with the matching signature
Map<Set<string> > keyedDictionary;
BuildDictionary(keyedDictionary, in);
while(true)
{
//prompt user for a word to solve
cout << "Enter a jumbled word to solve." << endl;
cout << "Type '0' to exit." << endl << endl;
string solveWord = GetLine();
if(solveWord == "0"){
break;
}
//sort the word into a signature key
solveWord = SortWord(solveWord);
//call the PrintSet(Set) member function to print the set of solutions for this signature key
PrintSet(keyedDictionary[solveWord]);
}
return 0;
}

Code reading extra line in my loop?

My goal is to read from an input file and count the number of lines that have at least 1 lowercase letter and 1 digit. I have already solved the rest of my code which counted all of the lowercase, uppercase, digits, characters and words no problem. I have also read from the input file and reversed the lines word by word. I cannot seem to figure out why the code is counting 8 lines when there are only 7 with 1 lowercase and 1 digit. While using getline() for all of the other loops, I've had no issues. I'm not looking specifically for someone to write the code for me. I'd just like an explanation of why this is happening if possible?
My input file contains:
This is a test file for hw3
How many Uppercase letters are in this f1le?
How many Lowercase letters are in this F1le?
H0W mAnY dIg1ts ar3 1N in this FILe?
Turn the 1npU7 N4m3 int0 its reverse
reverse the Lines to their opp05173 coutnerpart
find tOTal NumbEr of characTer5 in F1le
THIS IS A TEST LINE
My code for this section is:
inFile.clear();
inFile.seekg(0, inFile.beg);
while(getline(inFile, line)){
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
while(wordInput.get(c)){
if(islower(c)){
lowerCase++;
}
else if(isdigit(c)){
digit++;
}
}
if(lowerCase >= 1 && digit >= 1){
lineCount++;
}
}
cout << lineCount << endl;
return 0;
}
I have initialized all of my int variables to 0 and the top and I have declared my sstream variables as well. My libraries include <sstream> <fstream> <string> <iostream> and <algorithm> (which was used for earlier parts.
The output I am getting is
8
when it should be 7. The final line should not be counted as it has no lowercase letters and no digits. I am thinking that the first line is being read a second time and then stopping. I am in an intro to C++ class and have yet to learn how to use the debugger. Thank you in advance.
You made it clear that that you initialise all int variables to 0, which is great; however, let's have a look at your code (formatted so the indentation makes more sense):
// read line from file
while(getline(inFile, line))
{
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
// read character
while(wordInput.get(c))
{
if(islower(c))
{
lowerCase++;
}
else if(isdigit(c))
{
digit++;
}
}
if(lowerCase >= 1 && digit >= 1){
lineCount++;
}
}
Here you read a line, and go through all characters on that line, and if you find a lowercase character, or a digit, you increment a variable. What happens when you read the next line? You haven't reset those variables back to 0, so upon reading the next line they would both be above 1 already.
You need the following:
while(getline(inFile, line))
{
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
// We're about to start reading this line, so obviously we haven't found any yet
digit = 0;
lowerCase = 0;
Better yet, you can probably just declare those variables within the read line while loop:
while(getline(inFile, line))
{
int digit = 0;
int lowerCase = 0;
Although you haven't been taught to use a debugger, a great way of debugging is with cout statements. Put some print statements in to determine what all your variables are at any given time:
while(getline(inFile, line))
{
std::cout << "read line " << line << std::endl;
while(wordInput.get(c))
{
std::cout << "lowercase found so far: " << lowerCase << std::endl;
std::cout << "digits found so far: " << digit << std::endl;
if(islower(c))
{
std::cout << "lowercase character found: " << c << std::endl;
lowerCase++;
}
else if(isdigit(c))
{
std::cout << "digit found: " << c << std::endl;
digit++;
}
}
if(lowerCase >= 1 && digit >= 1)
{
std::cout << "found a lowercase character (" << lowerCase << ") or a digit (" << digit << ")" << std::endl;
lineCount++;
}
}
It's been awhile since I have coded in C++. There are other ways to debug than a debugger program.
I would add cout << line << endl; to your first while loop. That way you can output how the lines are being read and if any are being repeated. Also check your islower(char) and isdigit(char) functions to make sure they are reading appropriate ascii ranges.

While loop not seeing or finding terminating null character

I am trying to iterate through a char array using a while loop using '\0' as the terminating condition, but my problem is that its not finding the '\0' until index position 481, the array is declared as 200 long and I cant see what I am doing wrong!! I cannot use strings or any form of string functions for this before anyone asks. Can anyone help??
#include <iostream>
using namespace std;
int main()
{
char fullString[200]={'\0'}; // Declare char string of 200, containing null characters
int alphaCount = 0;
int charCount = 0;
int wordCount = 0;
cin.getline(fullString,200); //
cout << "\n\n" << fullString;
cout << "\n\n\n";
int i=0;
int i2 = 0;
while(fullString[i]!='\0'){ //iterate through array until NULL character is found
cout << "\n\nIndex pos : " << fullString[i]; //Output char at 'i' position
while(fullString[i2]!= ' '){ //while 'i' is not equal to SPACE, iterate4 through array
if(isalpha(fullString[i2])){
alphaCount++; // count if alpha character at 'i'
}
charCount++; // count all chars at 'i'
i2++;
}
if(charCount == alphaCount){ // if charCount and alphaCount are equal, word is valid
wordCount++;
}
charCount = 0; // zero charCount and alphaCount
alphaCount = 0;
i=i2;// Assign the position of 'i2' to 'i'
while(fullString[i] == 32){ //if spaces are present, iterate past them
i++;
cout << "\n\ntest1";
}
i2 = i; // assign value of 'i' to 'i2' which is the next position of a character in the array
if(fullString[i] == '\0')
{
cout << "\n\nNull Character " << endl;
cout << "found at pos: " << i << endl;
}
}
cout << "\n\ni" << i;
cout << "\n\nWord" << wordCount;
return 0;
}
As others have pointed out, your problem is with the inner loop. You test for a space character but not for NULL, so it's iterating past the end of the last word because there is no space character after the last word.
This is easily fixed by changing your while condition from this:
while(fullString[i2]!= ' ')
... to this:
while(fullString[i2] && fullString[i2]!= ' ')
This will change your inner while loop to first test for non-NULL, and then test for non-space.
I'm not correcting the rest of your code because I presume this is a class project (it looks like one) so I'm limiting my answer to the scope of your question.
You do not check in the inner loop
while(fullString[i2]!= ' '){ //while 'i' is not equal to SPACE, iterate4 through array
if(isalpha(fullString[i2])){
alphaCount++; // count if alpha character at 'i'
}
charCount++; // count all chars at 'i'
i2++;
}
...
i=i2;// Assign the position of 'i2' to 'i'
whether the next character is equal to '\0'
It's because the inner loops don't check for the termination, they just continue looping even past the end of the string.
By the way, if you want to count the number of words, spaces and non-space characters, there are easier ways in C++. See e.g. std::count and std::count_if for the spaces and characters. For example:
std::string input = "Some string\twith multiple\nspaces in it.";
int num_spaces = std::count_if(std::begin(input), std::end(input),
[](const char& ch){ return std::isspace(ch); });
For counting words, you can use std::istringstream, std::vector, std::copy, std::istream_iterator and std::back_inserter:
std::istringstream iss(input);
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(words));
After the code above, the size of the words vector is the number of words.
If you use e.g. std::copy_if then you can use the above code for the other cases as well (but std::count_if is better for single character classes).

How to convert vector to string and convert back to vector

----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.