Program Input only recognizing words not lines - c++

I wrote this program for a school project where the user inputs up to 4 lines of text then types "end" and it repeats it to them in reverse order. It works fine, except it is recognizing a "line" to be only 1 word so if I try and type a line (Ex. the quick brown fox jumps over the log) it doesn't use that as a line but each word as a line.
#include <iostream>
using namespace std;
#include <string>
int main()
{
string l1;
string l2;
string l3;
string l4;
string l5;
bool end (false);
while (end == false)
{
cout<<"Welcome! Type one sentence then press enter, up to 4 sentences. When finished$
cin >> l1;
if (l1 == "end")
{
cout << "Error! Must enter at least 1 line of text!" << endl;
break;
}
cin >> l2;
if (l2 == "end")
{
cout<<l1<<endl;
end = true;
break;
}
cin >> l3;
if (l3 == "end")
{
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
cin >> l4;
if (l4 == "end")
{
cout<<l3<<endl;
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
cin >> l5;
if (l5 == "end")
{
cout<<l4<<endl;
cout<<l3<<endl;
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
else
{
cout<<"Error! Please enter 4 or less lines"<<endl;
break;
}
}
}

Use std::getline instead of operator>>. The operator>> reads words, not text lines.

Related

Creating program to find repeated words in a sentence

I'm having trouble with this project because when I put a sentence such as "cat is not a dog", it will not say "Didn't find repeated word" as intended. Instead, it will say "Found repeated word", as if I it was true. Also, each time it is run for the first time, the first letter is removed from the user input. Why?
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include <time.h>
#include <stdio.h>
using namespace std;
int main()
{
int count = 0;
bool repeat = false;
char yn;
string input, newWord, firstword;
do
{
count = 0;
repeat = false;
cin.sync();
cout << "Please enter a sentence: ";
cin.ignore();
getline(cin, input);
while (input.at(count) != ' ')
count++;
firstword = input.substr(0, count);
input = input.substr(count++);
count = 0;
while(count < input.size() && repeat == false)
{
count++;
while (count < input.size() && input.at(count) != ' ')
count++;
newWord = input.substr(0, count);
if (firstword.compare(newWord) == 0)
input = input.substr(count++);
else
repeat = true;
}
if (repeat == true)
{
cout << "\nI found a repeated word!";
cout << "\nWould you like to try again? (y/n)";
cin >> yn;
}
else if(repeat == false)
{
cout << "\nI didn't find a repeated word.";
cout << "\nWould you like to try again? (y/n)";
cin >> yn;
}
} while (yn == 'y');
}
You program only checks if the first word is repeated annywhere else in the sentence...
Looking for a repeated word being: Each word must be checked against its immediate predecessor.
You're almost there. You forgot to reassign firstWord to newWord at te end of the parsing loop.
while(count < input.size() && repeat == false)
{
// ...
newWord = input.substr(0, count);
if (firstword.compare(newWord) == 0)
input = input.substr(count++);
else
repeat = true;
firstWord = newWord; // <-- Assign here.
}
Just an aside note, a trick of the trade, if you will.
if (repeat == true)
//...
else if(repeat == false) // <- Avoid doing that. Use plain else for booleans.
A bool can only have two values. And this kind of else if construct will bring unexpected surprises when plain ints are used for boolean equations. (if repeat was 3, which path does each cases of 0, 1, 3 follow?)
Have you tried removing the call to std::cin.sync() ?
Print your input after getline to be sure it's correctly saved. You probably don't need cin.ignore();. The first character is not saved.
An alternative sollution would be to use the following:
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <sstream>
using namespace std;
int main()
{
int pos = 0;
string input;
cout << "Please enter a sentence: ";
getline(cin, input);
map<string, int> count_words;
stringstream ss(input);
string word;
while(getline(ss, word, ' '))
count_words[word]++;
map<string, int>::const_iterator it;
for(it = count_words.begin() ; it != count_words.end() ; ++it)
if( it->second == 2)
cout << "Found duplicate: " << it->first << endl;
return 0;
}
this answer(https://stackoverflow.com/a/236803/4388908) provides a good method to split your input.
The rest: Programming Pearls by Jon Bentley

std::getline not re-requesting user input in while loop [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 2 years ago.
I am trying to write a program where a user is asked for input and then I check if the 2 sub strings (splitting in half) is the mirror image. I want to loop continually until a user stops entering in input but my code is not looping correctly. The code works fine on the first iteration of the while loop, but then during the second iteration of the while loop, getline() does not re-request user input, it just sets std::string input to "".
I'm sure I am missing something obvious.
Code
#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;
bool compareMirrorString(const std::string&, const std::string&);
int main()
{
std::string input;
string first_string;
string second_string;
bool result;
int input_length;
int first_string_length;
std::string quit;
cout << "Enter 2 strings to compare, seperated by a # e.g. \"abc#cba\"." << endl;
while ( true )
{
std::getline(std::cin, input);
//split string into its two component parts
input_length = input.length();
first_string_length = input_length / 2;
first_string.assign(input, 0, first_string_length);
second_string.assign(input, first_string_length + 1);
//test if two strings are mirror images of each other
result = compareMirrorString(first_string, second_string);
if (result) {
cout << "Yes they match.";
}
else {
cout << "No they do not match.";
}
cout << "\nDo you want to test another string? Y for yes, q to quit." << endl;
cin >> quit;
if (quit == "q" or quit == "Q" or quit == "quit" or quit == "Quit" or quit == "QUIT"
or quit == "no" or quit == "No")
{
break;
}
else
{
cout << "Enter another 2 strings to compare, seperated by a # e.g. \"abc#cba\"." << endl;
}
} //end of while
return 0;
}
//is second a mirror image of first?
bool compareMirrorString(const std::string& first, const std::string& second)
{
if (first.length() != second.length()) {
return false;
}
//put first_string on stack
std::stack<char> stackChar;
for (auto elem : first){
stackChar.push(elem);
}
int size = stackChar.size();
//compare first and second strings
bool compare_equal = true;
for (int i = 0; i < size; i++)
{
if (stackChar.top() == second[i])
{
stackChar.pop();
}
else
{
compare_equal = false;
break;
}
}
return compare_equal;
}
In the first iteration of the loop:
cin >> quit;
will read up to, but not including the newline character.
In the second iteration of the loop:
std::getline(std::cin, input);
will read that newline character, and hence read an empty string into input.
There are several ways to fix this
You could use getline to read the string quit
You could read input again, if it happens to be an empty string.
You could call cin.get(); after the cin >> quit to clear the newline.

spliting string input and find if characters are valid

It is possible to do next:
Let say I have a string "input" (that will be a input), I will cut this input in 2 parts, next, I will find if I entered first part only letters, and second part only digits? the code work only for letters but not for digits(remove comments, to see that all entered will be valid)
#include <iostream>
#include <string>
#include <iomanip>
#include <cctype>
using namespace std;
int main ()
{
while (true)
{
bool flag = false; // to check for numeric entry
string input; // not req to initialize
string input1;
cout << "Enter the string like ABC 123: ";
getline (cin, input);
if (input == "")
{
flag = true;
}
if (string::size_type pos = input.find (' '))//spliting the input in 2 if it will find a space
{
if (input.npos != pos)
{
input1 = input.substr (pos + 1);
input = input.substr (0, pos);
}
}
for (int i = 0; i < input.size (); i++)
{
// for (int n = 0; i < input1.size (); i++)
// {
int uppercaseCHar = toupper (input[i]);//checking if input(first part) contains only letters
if (!std::isalpha (uppercaseCHar))
{
// if(isdigit(input1[n]) == 0)//checing if input1(second part) contains only digits
// {
flag = true;
break;
// }
}
// }
}
if (input.compare ("1") == 0) break;//This will end program
{
flag = false;
}
if (flag)
{
cout << "Invalid!\n";
cout << endl;
} else
{
cout << "The string is valid! \n";
cout << endl;
}
}
}
Enter the string like ABC 123: QWE 123
The string is valid!
Enter the string like ABC 123: QW1 123
Invalid!
I don't have rights to comment yet, but if your first and second part of string don't have to be of same length, you can use the for loop two times for each sub string and then compare the values by one character at a time.
Also after checking for termination condition by
if (input.compare ("1") == 0) break;
you are adding a statement
{
flag = false;
}
this will set the result to false even if you have compared in your loop and found it TRUE,so take a look at following code below, i have commented that block of code out.
#include <iostream>
#include <string>
#include <iomanip>
#include <cctype>
using namespace std;
int main ()
{
while (true)
{
bool flag = false; // to check for numeric entry
string input; // not req to initialize
string input1;
cout << "Enter the string like ABC 123: ";
getline (cin, input);
if (input == "")
{
flag = true;
}
if (string::size_type pos = input.find (' '))//spliting the input in 2 if it will find a space
{
if (input.npos != pos)
{
input1 = input.substr (pos + 1);
input = input.substr (0, pos);
}
}
//cout<<"\n"<<input1;
//cout<<"\n"<<input;
//First check the letter part (first part) if it contains digits
for(int i=0;i<input.size();i++){
if(!std::isalpha(input[i])){
flag=true;
break;
}
}
//second check if the numeric part (second part) only contains digits
for(int i=0;i<input1.size();i++){
if(!std::isdigit(input1[i])){
flag=true;
break;
}
}
/*
for (int i = 0; i < input.size (); i++)
{
for (int n = 0; i < input1.size (); i++)
{
int uppercaseCHar = toupper (input[i]);//checking if input(first part) contains only letters
if (!std::isalpha (uppercaseCHar))
{
if(isdigit(input1[n]) == 0)//checing if input1(second part) contains only digits
{
flag = true;
break;
}
}
}
}
*/
if (input.compare ("1") == 0) break;//This will end program
//after checking for break, if you add flag=false, it will automatically ignore whatever flag you set, and you will always find FLAG=FALSE when compairing in upcoming lines
//{
// flag = false;
//}
if (flag)
{
cout << "Invalid!\n";
cout << endl;
} else
{
cout << "The string is valid! \n";
cout << endl;
}
}
}

Continually take input, and add values of input to a variable after keyword

I'm new to programming, and am taking a C++ class. Here's my assignment:
Write a program that continually takes in input until the user types “done”.
When the input received is a “+”, start adding together the values of each
subsequent input into a variable. When the input is a “-”, start subtracting
the values of the subsequent input from that same variable. Do nothing with
inputs that are received before either a “+” or “-” operation. Output the
final result to the screen.
This is what I have so far:
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
int main()
{
string input;
int number;
vector<int> numbers;
cout << "Type some stuff: \n";
for (;cin >> input && input != "done";)
{
if (input == "done")
break;
else if (input == "+")
cout << input;
}
return 0;
}
Here's the output:
Type some stuff:
Hello world done
HelloworldProgram ended with exit code: 0
I can't figure out the next part though. Thanks for the help.
From the assignment one can assume that inputs are words/numbers separated by a white space. The code line for (;cin >> input && input != "done";), which I suppose to be given as part of the assignment, supports this assumption. Then, the following input is supposed to achieve the following output:
100 200 + 100 200 - 10 done --> 290
Here's the code to achieve this:
int main()
{
string input;
int result;
int mode = 0;
cout << "Type some stuff: \n";
for (;cin >> input && input != "done";)
{
if (input == "done")
break;
else if (input == "+")
mode = 1;
else if (input == "-")
mode = -1;
else {
try {
int number = stoi(input);
number *= mode;
result += number;
}
catch( const std::exception& e ) { } // ignore any conversion errors
}
}
cout << result;
return 0;
}

Most common/idiotproof way to catch invalid input

I am getting into c++ right now, and right now I want to know the most common/best way to catch invalid input. I would love answers to this wide open question, but my more specific question is as follows.
I want a char from the user. If the char is 'y' then it will repeat, if it is 'n' then the program will close. If I enter multiple chars then it will repeat as many times as chars e.g. I enter 'hello' it will show my output 5 times. I assume that it reads each char and goes through the whole loop then reads the next char in line. How can I get it to show up just one time?
bool valid = 0;
while(valid)
{
...
bool secValid = 0;
while(secValid == 0)
{
cout << "To enter another taxable income type 'y': \n\n";
char repeat = NULL;
cin >> repeat;
if(repeat == 'y')
{
valid = 0;
secValid = 0;
system("cls");
}else if(repeat == 'n')
{
return;
}else
{
secValid = 1;
}
}
}
You could structure it something like this:
while(true) {
cout << "Repeat (y/n)? ";
string line;
if(!getline(cin, line))
break; // stream closed or other read error
if(line == "y") {
continue;
} else if(line == "n") {
break;
} else {
cout << "Invalid input." << endl;
}
}
Example session:
Repeat (y/n)? y
Repeat (y/n)? foo
Invalid input.
Repeat (y/n)? n
Here we use std::getline to get a whole line of input, instead of getting one character at a time.
std::getline():
std::string line;
std::getline(std::cin, line);
if (line == "y") {
// handle yes
}
else if (line == "n") {
// handle no
}
else {
// handle invalid input
}
use std::getline from the <string> header to read a line of input into a std::string
Also when checking string for "y" or "n" is good practise to use upcased string instead. For example
std::string YES = "Y";
std::string NO = "N";
...
std::string line;
std::getline(std::cin, line);
std::transform(line.begin(), line.end(), line.begin(), std::toupper);
if (line == YES)
{
...
}
else if (line == NO)
{
..
.
}