C++ white space string - c++

I'm brand new into C++. I would like to know, why my code is not working.
I've got string called Response.
If the response begins with y/Y it should proceed. However I would like to proceed when the user types " y"/" Y" (the white space) as well.
Here is my code.
Thanks in advance!
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
return (Response[0] == 'y') || (Response[0] == 'Y' +) ||(Response[0] == ' y' +) (Response[0] == ' Y' +);
std::cout << std::endl;
}

With Response[0] you access the first character of the string. You can compare that, as you do, with a character constant, such as 'y'. However, if you want to allow the leading space, this is no longer a single character, so your comparison Response[0] == ' y' cannot work.
Here is a version which allows as many space characters as needed, and then y or Y (C++11 version):
for (auto c:Response)
if (c!=' ')
return (c=='y') || (c=='Y');
//string is only spaces
return false;

You can traverse string Response and ignore white spaces(I am considering Tabs and Spaces in this case) while traversing.
If first character is non white space then you can break the loop I am using flag yes in this case.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
auto Response="";
std::getline(std::cin, Response);
auto yes = false;
auto itr = Response.begin();
while(itr != Response.end())
{
if(*itr != ' ' && *itr !='\t')
{
yes = (*itr == 'y' || *itr =='Y') ;
break;
}
++itr;
}
return yes;
}

You can remove the spaces from the response and check with only 'Y'/'y'.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
Response.erase(remove(Response.begin(), Response.end(), ' '), Response.end());
return (Response[0] == 'y') || (Response[0] == 'Y');
}

Use a loop to check each of your character inside the input string...
For example, like this, usage of the usual loop which can be used in all versions of C++ (You can use the range based for loop like in the above answer...):
bool ask_to_play_again(std::string Response)
{
for (auto i = 0; i < Response.size(); i++)
if (!isspace(Response[i])) // Is not a whitespace character
return tolower(Response[i]) == 'y';
return false; // If the user enters invalid input, close the game anyway...
}
Kind regards,
Ruks.

Maybe you can use std::find function to resolve the problem.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
auto pos1 = Response.find("Y");
auto pos2 = Response.find("y");
if (pos1 != std::string::npos || pos2 != std::string::npos)
return true;
return false;
}

Related

Get yes/no in console always fails

I'm trying to make a program that will run over and over again, provided the user says yes every time. Unfortunately, it doesn't seem to recognize when I input yes or no into it, and always does the default "Come again?" message. This is the code I'm using to get the input from the console:
bool getYN(){
bool confirmed = 0;
bool answer = 0;
string input;
while(!confirmed){
getline(cin, input, '\n');
transform(input.begin(), input.end(), input.begin(), toupper);
if(input.c_str() == "Y" || input.c_str() == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input.c_str() == "N" || input.c_str() == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
} else { //If the user says something else entirely
printf("\nCome again? (Y/N) ");
};
};
return answer;
};
I have included <string> and <algorithm>. For some reason, it always acts like it's not getting y/yes or n/no when I type them in. It just keeps asking me to answer again.
if(input.c_str() == "Y" || input.c_str() == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input.c_str() == "N" || input.c_str() == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
}
You should not be doing c-string comparisons like this. You're taking the address of a char and comparing against the address of a text-allocated object. Of course the comparison is going to return false.
With c++ strings, simple operator== comparisons are valid:
if(input == "Y" || input == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input == "N" || input == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
}
#include <iostream>
#include <string>
using namespace std; // For speed
int main()
{
bool saidYes = false;
string input;
while (!saidYes)
{
cout << "Input yes or no: ";
getline(cin, input);
if (input == "no" || input == "n" || input == "NO")
{
saidYes = true; // breaks the loop
}
if (input == "y" || input == "Y" || input == "yes" || input == "YES")
{
saidYes = false;
}
}
return 0;
}
You can use the above example to eliminate a huge portion of unnecessary code, I chose not to add the else statement but it will work if you add that here as well.
You can also condense this code even further but this was only intended to be a simple example as to how to better get this working for you!
As it was said above you can use == to compare the strings, if you're coming from certain other languages it can be an annoying change to get used to lol.
I have included string and algorithm. For some reason, it always acts like it's not getting y/yes or n/no when I type them in. It just keeps asking me to answer again.
algorithm is not required for what you're trying to do, and your making the reading and acceptance of the string input much more difficult than it needs to be.
If you look above you'll see the string input; This is going to be your variable that you can use to store the user input string into.
You'll also notice getline(cin, input); This is what you can use to "read" the string that the user enters when they're prompted to.
#Kelvin Shadewing My initial answer was only directed at your Question, this next example is directed to your comment to me below!
So you've got quite a few options but assuming that you want the user to input either yes or no and depending on the input you want to produce a specific result while ensuring that the user is prompted over and over again to input either yes or no all you have to is modify my original answer like so.
#include <iostream>
#include <string>
using namespace std; // For speed
int main()
{
bool saidYes = false;
string input;
while (!saidYes)
{
cout << "Input yes or no: ";
getline(cin, input);
if (input == "no" || input == "n" || input == "NO")
{
saidYes = true;
cout << "you said no" << endl;
/* breaks the loop by changing the
bool (true or false flag) to true, if you want to produce a specific result,
whether it's a simple output statement or a function call you can put it here
*/
}
else if (input == "y" || input == "Y" || input == "yes" || input == "YES")
{
saidYes = true;
cout << "You said yes" << endl;
/* breaks the loop by changing the
bool (true or false flag) to true, if you want to produce a specific result,
whether it's a simple output statement or a function call you can put it here
*/
}
else saidYes = false;
}
return 0;
}
I've modified my code based on the current best answer, but I've also optimized it so that confirmed is no longer necessary.
bool getYN(){
bool answer = 0;
string input;
while(!answer){
getline(cin, input, '\n');
transform(input.begin(), input.end(), input.begin(), toupper);
if(input == "Y" || input == "YES"){
answer = 2;
} else if(input == "N" || input == "NO"){
answer = 1;
} else {
printf("\nCome again? (Y/N) ");
};
};
return answer - 1;
};
Small optimization, sure, but every little bit counts.

String and Bool (Int Condition to be false) C++

Im new to C++ and I tried searching but I have no idea on what to search. Sorry. My problem is:
When I set the bool condition false, it still requires me to input 2 x to terminate the compiler. Why is that so? (I tried using cin.fail () but it didnt work)
When I print the list of courses, it lists the one that should terminate the program (ie when you press x). How do I correct this?
Thank you for your help.
int main(void)
{
// Gather list of courses and their codes from user,
// storing data as a vector of strings
const string DegreeCode("PHYS");
string CourseTitle;
int CourseCode(0);
vector <string> CourseList;
vector <string> :: iterator iter;
bool not_finished(true);
do
{
if (CourseTitle == "x" && "X")
{
not_finished=false;
}
else
{
cout<<"Please enter a course code and a course title (or x to finish): "<<endl;
cin>>CourseCode;
cin.sync();
cin.clear();
getline(cin , CourseTitle);
ostringstream oss;
string outputCourseList (oss.str ());
oss << DegreeCode << " " << CourseCode << " "<< CourseTitle;
CourseList.push_back (oss.str ());
cout <<outputCourseList <<endl;
oss.str(""); //clear oss content
}
} while(not_finished);
// Print out full list of courses
cout<<"List of courses:\n"<<endl;
for (iter = CourseList.begin(); iter != CourseList.end(); iter++)
cout<<(*iter)<<endl;
return 0;
}
Your problem is your comparison in the if statement:
if (CourseTitle == "x" && "X")
The proper syntax is: (variable operator variable) && (variable operator variable)
The syntax corrected:
if ((CourseTitle == "x") && (CourseTitle == "X"))
There is a logic issue because a variable can't equal two values at the same time.
Maybe you want:
if ((CourseTitle == "x") || (CourseTitle == "X"))
which means one OR the expressions is true.
You could eliminate the two compares by transforming the string into all uppercase or all lowercase. Search the web for "C++ string transform tolower toupper".
if (CourseTitle == "x" && "X")
{
not_finished=false;
}
to
if (strcmp(CourseTitle.c_str(), "x") == 0 || strcmp(CourseTitle.c_str(), "X") == 0)
{
not_finished=false;
}
== is a pointer comparison, almost never true... "x" == "x" will even be false unless you're good with compiler flags
Make sure to
#include <string.h> //<----.h is needed!

Expression: string subscript out of range. Attribute passing issue?

I am running into an error during my program's runtime:
"Debug Assertion Failed! ... Expression: string subscript out of range."
This is happening in my for loop when my if statement attempts to check if the character at 'i' in the string isDelimiter() or isOperator(). I am passing the char 'check' as an attribute, and in the comments I have made sure that 'check' is grabbing the correct character. I've been working on this issue for a while and I can't seem to resolve it.
EDITED AT BOTTOM
string inputLine = "";
string inputString = "";
int main()
{
ifstream input("input.txt");
getline(input, inputLine);
if (input.is_open())
{
while (!input.eof())
{
getline(input, inputLine);
for (int i = 0; i<inputLine.length(); i++)
{
char check = inputLine[i];
//cout << check << "\n"; // test for correct character
if ((inputLine[i] != ' ') || (inputLine[i] != isDelimiter(check)) || (inputLine[i] != isOperator(check)))
{
inputString = inputString + inputLine[i];
//cout << lexer(inputString) << "\n";
//cout << inputString;
} // end if
else
{
cout << lexer(inputString);
if (inputLine[i] == isDelimiter(i))
cout << inputLine[i] + "\tDELIMITER";
if (inputLine[i] == isOperator(i))
cout << inputLine[i] + "\tOPERATOR";
inputString = "";
} // end else
//cout << inputString << "\n";
} // end for
} // end while
//input.close();
}
else cout << "Unable to open file.";
return 0;
}
Here are the isDelimiter() and isOperator() methods.
bool isOperator(char c)
{
if ((inputLine[c] == '+') || (inputLine[c] == '-') || (inputLine[c] == '*') || (inputLine[c] == '/') || (inputLine[c] == '=') || (inputLine[c] == '%') || (inputLine[c] == '<') || (inputLine[c] == '>'))
return true;
else
return false;
}
bool isDelimiter(char c)
{
if ((inputLine[c] == ';') || (inputLine[c] == '(') || (inputLine[c] == ')') || (inputLine[c] == ','))
return true;
else
return false;
}
Any help is appreciated!
EDIT::
After reviewing my code some more I realized the mistake, but I still have another. That runtime error was because in my isOperator() and isDelimiter() functions, I was checking inputString[c] rather than just 'c'. Silly mistake, I know. However, although there is no longer an error, the program still skips checking the isOperator() and isDelimiter() methods, and only goes into the else statement when it reads a ' '. Why isn't it going into my else statement for operators and delimiters?
Your functions take char, change them to int:
bool isDelimiter(char c) //should be int
{
if ((inputLine[c] == ';') || (inputLine[c] == '(') || (inputLine[c] == ')') || (inputLine[c] == ','))
return true;
else
return false;
}
I figured it out, and even though they're simple mistakes, maybe it'll help somebody in the future. After all, I was stumped for a while.
They were mainly just syntax errors, I really needed to freshen up on my coding.
This is the format my functions now follow. Notice I'm finally passing the correct values.
bool isDelimiter(char c)
{
if ((c == ';') || (c == '(') || (c == ')') || (c == ','))
return true;
else
return false;
}
And this is how I am now calling them. I was trying to check if the input itself was equal to the function, which would be like asking if "helloworld" == TRUE. Obviously that wasn't working, and I wanted to kick myself once I figured that out. Here's the snippet:
if ((inputLine[i] == ' ') || (isDelimiter(check)) || (isOperator(check)))
{
cout << lexer(inputString);
if (isDelimiter(check))
{
cout << inputLine[i] << "\t\tDELIMITER\n";
}
if (isOperator(check))
{
cout << inputLine[i] << "\t\tOPERATOR\n";
}
inputString = "";
} // end if
else
{
inputString = inputString + inputLine[i];
} // end else
That has resolved my basic issues, now onto bigger ones.

Or operator not working

When I enter start then the program outputs the else function even though I fulfilled the criteria, I have tried with && as well and it still didn't work. Any answers would be appreciated.
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main ()
{
float timer;
bool end;
std::string input;
end = false;
cout << "Enter start then a number to count down from" << ".\n";
while (end == false){
cin >> input;
if (input.find("end" || "End") != std::string::npos)
end = true;
else if (input.find("start" || "restart" || "Start" || "Restart") != std::string::npos)
{
cin >> timer;
while (timer>0){
timer -= 0.1;
Sleep(100);
cout << timer << ".\n";
}
cout << "Finished! Enter restart then another number to perform another countdown, or enter end to close the program" << ".\n";
}
else
cout << "Enter start" << ".\n";
}
return 0;
}
Replace
if (input.find("end" || "End") != std::string::npos)
with:
if (input.find("end") != std::string::npos || input.find("End") != std::string::npos)
Similarly for your other if.
It seems obvious what your expression means, but when you break it down it really doesn't make sense. find expects a string, and "end" || "End" is not a string.
the Logical or operator, || only works in boolean expressions.
For instance, if you had
bool A = true
bool B = false
bool C = A||B;
than you will have set bool C to be True. IT just takes 2 booleans, and returns true if either of those booleans is true. That's all logical or does.
You might want to try something like
if (input.find("end") != std::string::npos || input.find("End") != std::string::npos)
The || works only in logical boolean expression.
From the standard (emphasis is mine):
5.15 Logical OR operator [expr.log.or]
The || operator groups left-to-right. The operands are both contextually converted to bool (Clause 4). It returns true if either of its operands is true, and false otherwise.
So in input.find("end" || "End"), it tries to convert "end" and "End" to bool. And the operator || will return a bool also.
Here to solve your problem you need to replace:
if (input.find("end" || "End") != std::string::npos)
by
if ( input.find("End") != std::string::npos ||
input.find("End") != std::string::npos )
And do the same in the second find.
C++ simply doesn't work that way. When you write
input.find("end" || "End") != std::string::npos
the compiler sees the logical or on two non-null const char pointers, which results in the boolean value true. This is then interpreted as a char with the value 1 ('\1') which is then searched in the string - certainly not what you intended. If you want to know if you string is in a set of strings, you could use:
static std::set<std::string> s = { "end", "End" };
s.find( input ) != s.end();
While maybe not the most efficient code in the world, but with a C++11 compiler you can also condense it into a single line like this:
if( std::set<std::string>{ "end", "End" }.count( input ) ) {
// found...
}
if (input.find("end" || "End") != std::string::npos)
// ^^^^^^^^^^^^^^
The || operator is not being used correctly here. The righthand expression will return true because it is non-zero, then it will be returned. So the statement resolves to input.find("end"). You need to use two separate conditional statements there:
if (input.find("end") != std::string::npos ||
input.find("End") != std::string::npos)
I'd recommend using regex instead for things like that:
regex
The argument of the function call
input.find("end" || "End")
has type bool and means that addess of string literal "end" or/and address of string literal "End" is not equal to zero. It is obvious that the both string literals have addresses that are not equal to zero. So the call is equivalent to
input.find(true)
The compiler finds an overloaded function find that is the most suitable for this argument. This function is
find( charT, c, size_tipe pos = 0 );
Value true is implicitly converted to value charT( 1 ) and the function tries to find char with value 1 in your string.
here is a fix:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main()
{
float timer;
bool end;
std::string input;
end = false;
cout << "Enter start then a number to count down from" << ".\n";
while (end == false) {
cin >> input;
if (input.find("end") != std::string::npos | input.find("End") != std::string::npos)
end = true;
else if (input.find("start") != std::string::npos | input.find("Start") != std::string::npos | input.find("restart") != std::string::npos | input.find("Restart") != std::string::npos)
{
cin >> timer;
while (timer > 0) {
timer -= 0.1;
Sleep(100);
cout << timer << ".\n";
}
cout << "Finished! Enter restart then another number to perform another countdown, or enter end to close the program" << ".\n";
}
else
cout << "Enter start" << ".\n";
}
return 0;
}
it should be like this if (input.find("end") != std::string::npos | input.find("End")!= std::string::npos or this if (input.find("end") != std::string::npos || input.find("End")!= std::string::nposinstead of if (input.find("end" || "End") != std::string::npos)you can use logical or or bitewise or.

Char validator will not only accept lower and upper case M/F

Hey im trying to validate a char to limit it to accpeting an m or f for male or female. But it doesnt pass the while condition even when m or f is pressed and keeps looping the question.
Can anybody help me with this.
Thanks in advance.
Here is my code:
char Validator :: getChar(string q)
{
char input;
do
{
cout << q.c_str() << endl;
cin >> input;
}
while(!isalpha(input) && "M"||"F"||"m"||"f");
return input;
}
The "M"||"F"||"m"||"f" part of your code doesn't do what you think it does. What it does is check the ADDRESSES of those string constants. Since they are all non-NULL, this expression simply returns true, so your condition, essentially becomes: while(!isalpha(input) && true) which is the same as while(!isalpha(input)).
Try this instead:
char Validator::getChar(const string &q)
{
char input = 0;
do
{
cout << q << endl;
cin >> input;
}
while((input != 'M') && (input != 'F') && (input != 'm') && (input != 'f'));
return input;
}
The expression in the while doesn't mean what you think it does. First, the ! does not apply to the entire expression, and second, "equality" is not an implicit test. You need to write out everything you mean.
To test for equality, use the == or != operators. You have to use the operators on every value you want to test; the operator doesn't "distribute" over a list of values like it would in ordinary English. Write your condition like this:
while (input != 'M' && input != 'F' && input != 'm' && input != 'f');
You can see that the isalpha call isn't necessary; if input isn't equal to any of the listed values, then it doesn't really matter whether it's an alphabetical character.
Another way to write it is this:
while (!(input == 'M' || input == 'F' || input == 'm' || input == 'f'));
Notice that I've another set of parentheses around the internal terms so that the ! operator applies to the entire expression instead of just the first term.
Just for an alternative approach to the terminating condition:
char Validator::getChar(const string &q)
{
const std::set<char> valid_chars { 'M', 'm', 'F', 'f' };
char input = 0;
do
{
cout << q << endl;
cin >> input;
}
while (!valid_chars.count(q));
return input;
}