How to read a vector of strings from stdin in c++ - c++

From the book "Accelerated C++":
Ex 4-5-> Write a function that reads words from an input stream and stores them in a vector. Use that function both to write programs that count the number of words in the input, and to count how many times each word occurred.
This is the code I am trying to run:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin; using std::cout;
using std::vector; using std::sort;
using std::endl; using std::string;
using std::istream;
istream& read_words(istream& in, vector<string>& words) {
if (in) {
words.clear();
string word;
while (in >> word)
words.push_back(word);
in.clear();
}
return in;
}
int main() {
vector<string> words;
read_words(cin, words);
cout << "Num of words: " << words.size() << endl;
sort(words.begin(), words.end());
string prev_word = "";
int count = 0;
for (vector<string>::size_type i = 0; i < words.size(); ++i) {
if (words[i] != prev_word) {
if (prev_word != "")
cout << prev_word << " appeared " << count << " times" << endl;
prev_word = words[i];
count = 1;
}
else
++count;
}
cout << prev_word << " appeared " << count << " times" << endl;
return 0;
}
Now, when I try to run the code, it gets stuck at the input and keeps reading
until I abort the program using Ctrl+C. What is wrong with my code?

Related

3-3. Write a program to count how many times each distinct word appears in its input

In this:
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::cin; using std::vector; using std::endl;
using std::string;
int main(){
cout << "enter strings: " << endl;
string s;
vector<string> in;
vector<string> out;
vector<int> count;
while(cin >> s)
in.push_back(s);
out.push_back(in[0]);
count.push_back(1);
int index = 0;
for(int i=0;i<in.size();i++){
if(out[index]==in[i])
(count[index])++;
else{
out.push_back(in[i]);
count.push_back(1);
index++;
}
}
cout << endl;
for(int i=0;i<count.size();i++)
cout << "i: " << i << "\tval: " << count[i] << endl;
}
I am not sure hot make the variable index to move only forward in count vector to count only those words that have already occure. Can someone help? exercise from book Accelerated C++ Practical Programming by Example
If you can't use std::map, you can associate the word with the frequency:
struct Info
{
std::string word;
int frequency;
};
//...
std::vector<Info> database;
//...
std::string word;
while (std::cin >> word)
{
// Find the word:
const size_t length = database.size();
for (unsigned int i = 0; i < length; ++i)
{
if (database[i].word == word)
{
database[i].frequency++;
break;
}
}
if (i >= length)
{
Info new_info{word, 0};
database.push_back(new_info);
}
}
The above code also shows that you should only insert words that are duplicates. No need to input all the words, then do the processing.

For each distinct word in the file, display a count of the number of times that word appears in the file

This is one of my homework and I keep running into seg fault after the cin while loop, can anybody tell what did I do wrong? I have not learn map yet so I can't do that. One of my thought is that it went into seg fault because I was comparing the two string elements inside the vector, what is the way to do that properly?
#include <chrono>
#include <climits>
#include <cfloat>
#include <limits>
#include <cassert>
#include <exception>
#include <cctype>
#include <string>
#include <cmath>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <regex>
#include <vector>
using namespace std;
int main()
{
vector<string> word_input;
vector<int> word_count;
string word;
string fileName;
ifstream inputFile;
cout << "Enter file name: ";
getline(cin,fileName);
inputFile.open(fileName);
while (inputFile.fail())
{
cout << "Can't open the file" << endl;
exit(1);
}
cout << "File opened successfully \n";
while (inputFile >> word)
{
if (word != word_input.back())
{
word_input.push_back(word);
word_count.push_back(1);
}
else
{
word_count.push_back( word_count.back() + 1);
}
}
int count =word_count.back();
// Compare the input words
// and output the times of every word compared only with all the words
for (int i = 0; i != count; ++i)
{
int time = 0;
for (int j = 0; j != count; ++j)
{
if (word_input[i] == word_input[j])
++time;
}
std::cout << "The time of "
<< word_input[i]
<< " is: "
<< time
<< endl;
}
inputFile.close();
return 0;
}
The strategy you are using is fraught with problems. A simpler approach would be to use a std::map<std::string, int>.
int main()
{
std::map<std::string, int> wordCount;
string word;
string fileName;
ifstream inputFile;
cout << "Enter file name: ";
getline(cin,fileName);
inputFile.open(fileName);
if (inputFile.fail())
{
cout << "Can't open the file" << endl;
exit(1);
}
cout << "File opened successfully \n";
while (inputFile >> word)
{
// --------------------------------------------------------------
// This is all you need to keep track of the count of the words
// --------------------------------------------------------------
wordCount[word]++;
}
for ( auto const& item : wordCount )
{
std::cout << "The time of "
<< item.first
<< " is: "
<< item.second
<< std::endl;
}
inputFile.close();
return 0;
}

Validate case pattern (isupper/islower) on user input string

I need to write a program that checks if the user-provided first and last names are correctly typed. The program needs to validate that only the first letter of each name part is uppercase.
I managed to write code that checks the first character of the input. So I have a problem when for example "JOHN" is entered.
A correct input would be for example "John Smith".
Here's the code:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
std::string str;
cout << "Type First Name: ";
cin >> str;
if(isupper(str[0]))
{
cout << "Correct!" <<endl;
}
else
{
cout << "Incorrect!" <<endl;
}
system("pause");
return 0;
}
The simplest thing you can do is to use a for/while loop. A loop will basically repeat the same instruction for a number of n steps or until a certain condition is matched.
The solution provided is pretty dummy, if you want to read the first name and last name at the same time you will have to spit the string via " " delimiter. You can achieve this result using strtok() in C/C++ or with the help of find in C++. You can see some examples of how to split here.
You can easily modify your code to look like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
std::string str;
std::vector<std::string> data = { "First", "Last" };
int j;
for (int i = 0; i < 2; i++) {
cout << "Type " << data[i] << " Name: ";
cin >> str;
if (isupper(str[0])) {
for (j = 1; j < str.size(); j++) {
if (!islower(str[j]))
{
cout << "InCorrect!" << endl;
break; // Exit the loow
}
}
if(j==str.size())
cout << "Correct!" << endl;
}
else {
cout << "InCorrect!" << endl;
}
}
system("pause");
return 0;
}

beginner :While loop not working as it should

I am still a beginner and I am learning from a book. There was a drill that asked me filter input based on a vector of filtered words and if it was one of them it outputs "bad word"
Here is the drill exactly as in the book.
Try This
Write a program that “bleeps” out words that you don’t like; that is, you read in words using cin and print them again on cout. If a word is among a few you have defined, you write out BLEEP instead of that word. Start with one “disliked word” such as string disliked = “Broccoli”
When that works, add a few more.;
Here is the code I wrote:
#include <D:\std_lib_facilities.h>
int main()
{
// RL: omitting actual "bad" words to protect the innocent...
vector <string> bwords { "word1", "word2", "word3" };
vector <string> words;
string input = "";
while(cin >> input)
{
words.push_back(input);
}
double counter1 = 0;
double counter2 = 0;
while(counter1 < bwords.size() && counter2 < words.size())
{
if(bwords[counter1] == words[counter2])
{
cout << " bad word ";
}
else if (counter1 == bwords.size() - 1 && counter2 != words.size() )
{
cout << " "<< words[counter2] <<" ";
counter1 = 0;
}
else
{
++counter1;
counter2 += 1 / bwords.size();
}
}
}
whenever it starts it just tests the first word and repeats its self as if just tests the first if condition.
You over-complicated your loop. Try something more like this instead:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
int main()
{
vector <string> words;
string input;
while (cin >> input)
words.push_back(input);
for (int counter = 0; counter < words.size(); ++counter)
cout << " " << bleepWordIfBad(words[counter]) << " ";
/*
Alternatively:
for (vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
cout << " " << bleepWordIfBad(*iter) << " ";
*/
/*
Alternatively:
for (const string &word : words)
cout << " " << bleepWordIfBad(word) << " ";
*/
return 0;
}
Or, get rid of the manual loop altogether:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
void outputWord(const string &word)
{
cout << " " << bleepWordIfBad(word) << " ";
}
int main()
{
vector <string> words;
string input;
while (cin >> input)
words.push_back(input);
for_each(words.begin(), words.end(), outputWord);
/*
Alternatively:
for_each(words.begin(), words.end(),
[](const string &word) { cout << " " << bleepWordIfBad(word) << " "; }
);
*/
return 0;
}
Or, get rid of the input vector altogether and just filter the user's input as it is being entered:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// RL: omitting actual "bad" words to protect the innocent...
const vector <string> bwords { "word1", "word2", "word3" };
string bleepWordIfBad(const string &word)
{
if (std::find(bwords.begin(), bwords.end(), word) != bwords.end())
return "BLEEP";
else
return word;
}
int main()
{
string word;
while (cin >> word)
cout << " " << bleepWordIfBad(word) << " ";
return 0;
}

Search word not found in a vector?

I'm implementing a function where the user can search for a word in a vector. The only problem is, my search function is only finding certain words and I'm not sure why.
ifstream in("testdata.txt");
string word1;
vector<string> individual_words;
while (in >> word1)
{
individual_words.push_back(word1);
}
Inside the file testdata.txt is:
Hello how are you
Good are you well?
Snazzy piece of toast
Here is the code where I compare the two words.
string search_word;
while (cin >> search_word)
{
for (int f=0; f < individual_words.size(); f ++)
{
cout << "individual words: " << individual_words[f] <<endl;
cout << "search word: " << search_word;
if (search_word == individual_words[f])
{
cout << " FOUND THE SAME WORD\n!";
break;
}
}
}
For some reason it's only catching certain words in a .txt file and I'm not exactly sure why. I've looked at it and it looks like it ignores the first word and it ignores every last word on each sentence.
Your vector will have duplicates, so it will only find the first occurrences of the words "are" and "you" before your loop breaks. Logically, there is nothing else wrong in this section of code, though it would be better written as:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
// simplified for demonstration purposes
string test = "Hello how are you\nGood are you well?\nSnazzy piece of toast";
istringstream iss(test);
vector<string> words;
copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(words));
string search_word;
while (cin >> search_word)
{
// this works, but is unnecessary
/*for (int f=0; f < words.size(); f ++)
{
cout << "individual words: " << words[f] <<endl;
cout << "search word: " << search_word;
if (search_word == words[f])
{
cout << " FOUND THE SAME WORD\n!";
break;
}
}*/
// this is a better approach
vector<string>::iterator it = find(words.begin(), words.end(), search_word);
if (it != words.end())
{
cout << "Found the word: " << *it << endl;
}
else
{
cout << "Not found!" << endl;
}
}
return 0;
}