C++ if statement not parsing whitespace - c++

My if statement in a c++ console application is not working:
string line;
cin >> line;
if (line == "a b"){
cout << "lalala";
}
When I type "a b" nothing happens.
if i use if (line == "ab") and type ab it works.

std::cin reads delimited by white-space. So when you read cin >> line you are only reading "a" from "a b". Use std::getline(std::cin, line) to read the entire line, including white-space (not '\n').
BTW, you could have easily found this problem by looking at your variables with a debugger, or by printing it. Debug your code before posting questions.
NOTE: By std::cin I mean the operator>>, which has many overloads, as non-members and istream members. The overload that takes a std::string reads delimited by white-space.

Because the reading will end till the whitespace, that means line will be "a" here.
See operator>>(std::basic_string)
until one of the following conditions becomes true:
std::isspace(c,is.getloc()) is true for the next character c in is (this whitespace character remains in the input stream).

Related

Extraction Operator reaching EOF on istringstream, behavioral change with int/char/string

So I am doing some simple file I/O in c++ and I notice this behaviour, not sure if I am forgetting something about the extraction operator and chars
Note that the file format in Unix.
ifstream infile("test.txt");
string line;
while(getline(infile, line)){
istringstream iss(line);
**<type>** a;
for(...){
iss >> a;
}
if(iss.eof())
cout << "FAIL" << endl;
}
Say that the input file test.txt looks like this and the <type> of a is int
$ is the newline character (:set line)
100 100 100$
100 100 100$
what I notice is that after the first line is read, EOF is set true;
If the input file is like so, and the <type> of a is char:
a b c$
a b c$
Then the Code behaves perfectly as expected.
From what I understand about File I/O and the extraction operator, the leading spaces are ignored, and the carriage lands on the character after the input is taken out of the input stringstream iss. So in both cases, at the end of each stringstream the carriage lands on the newline character, and it shouldn't be an EOF.
Changing the <type> of a to string had similar failure as <type> = int
BTW failbit is not set,
at the end:
good = 0
fail = 0
eof = 1
getline has extracted and discarded the newline, so line contains 100 100 100, not 100 100 100$, where $ is representing the newline. This means reading all three tokens from the line with a stringstream and the >> operator may reach the EOF and produce the FAIL message.
iss >> a; when a is an int or a string will skip all preceding whitespace and then continue extracting until it reaches a character that can't possibly be part of an int or is whitespace or is the end of the stream. On the third >> from the stream, the end of the stream stops the extraction and the stream's EOF flag is set.
iss >> a; when a is an char will skip all preceding whitespace and then extract exactly one character. In this case the third >> will extract the final character and stop before seeing the end of the stream and without setting the EOF flag.

Extraction operator into non-numeric character

Given an istringstream, is it possible to "extract" its contents into a character only if the character to be extracted is non-numeric (i.e. not 0-9)?
For example, this
string foo = "+ 2 3";
istringstream iss(foo);
char c;
iss >> skipws >> c; //Do this only if c would be non-numeric
should extract '+', but if foo were "2 + 3", it shouldn't extract anything, since the first [non-whitespace] character is '2', which is numeric.
To give some context, I need this to make a recursive "normal polish notation" (i.e. prefix notation) parser.
You can use unget to put back the character if it is numeric.
string foo = "+ 2 3";
istringstream iss(foo);
char c;
iss >> skipws >> c;
if (std::isdigit(c)) iss.unget();
You can use istream::peek to check what the next character will be before extracting it. You can test the result of peek against your acceptable range, and if it matches, do the actual extraction.
BTW, if you want to skip whitespace, you'll also need to check for and handle that with peek() (by extracting and discarding whitespace characters). Even with skipws, peek() won't peek past the whitespace.

For scanf(), why is negated scanset "%[^\n]" showing correct output for "\n", but not the scanset "%[aeiou]" for "aegis"?

In the following program, if I use the line for the negated scanset, it works fine if I enter a multi-word line (ending with ENTER or newline), even though the newline is in the negated list.
But if I use the line for the scanset instead and enter the word "aegis" (or any word with consonants for that matter), then junk characters are output. Analogous to the first case, shouldn't at least "ae" be output if I enter this word? Please explain this behavior of scanset and negated scanset for scanf().
#include <stdio.h>
int main ()
{
char str[30];
printf("Enter the string\n");
//scanf("%[^\n]",str);
//scanf("%[aeiou]",str);
printf("%s",str);
}
It is because code errantly does not check the return value of scanf()
printf("Enter the string\n");
scanf("%[^\n]",str);
scanf("%[aeiou]",str); // check result before using `str`
printf("%s",str);
With scanf("%[^\n]",str); and input like "123\n", str get the values of "123" and '\n' remains in stdin. Then with scanf("%[aeiou]",str); and input like "aegis\n", the first line's '\n' blocks saving anything as '\n' is not a vowel, nothing is saved in str and since code did not check the return value of scanf(), does not realized that str may be invalid.
1) Always check the return value of scanf() and family.
if (scanf(some_format, var1, var2, ...) != ExpectedConversionCount) {
Fail();
}
2) scanf("%[^\n]",str); to read a line fails 3 things: No input limit, fails to read anything if the the line consists of only '\n'. Without check the return value, EOF is not detected.
3) Use fgets() instead of scanf() for user input.

reading a file word by word

I can read from a file 1 character at a time, but how do i make it go just one word at a time? So, read until there is a space and take that as a string.
This gets me the characters:
while (!fin.eof()){
while (fin>> f ){
F.push_back ( f );
}
If your f variable is of type std::string and F is std::vector<std::string>, then your code should do exactly what you want, leaving you with a list of "words" in the F vector. I put words in quotes because punctuation at the end of a word will be included in the input.
In other words, the >> operator automatically stops at whitespace (or eof) when the target variable type is a string.
Try this:
std::string word;
while (fin >> word)
{
F.push_back(word);
}

String vectors not working as expected with newline and iterators? (C++)

I have a text file made of 3 lines:
Line 1
Line 3
(Line 1, a blank line, and Line 3)
vector<string> text;
vector<string>::iterator it;
ifstream file("test.txt");
string str;
while (getline(file, str))
{
if (str.length() == 0)
str = "\n";
// since getline discards the newline character, replacing blank strings with newline
text.push_back(str);
} // while
for (it=text.begin(); it < text.end(); it++)
cout << (*it);
Prints out:
Line 1
Line 3
I'm not sure why the string with only a newline was not printed out. Any help would be appreciated. Thanks.
Wasn't? Actually, it was! The reason you have a newline after Line 1 is exactly that empty string with newline in it and nothing else. If not for that second line, you'd see Line 1Line 3 as output. (You said it yourself: getline discards newline characters.)
Apparently, the way I understand your intent, you were supposed to implement your output cycle as follows
for (it = text.begin(); it < text.end(); it++)
cout << *it << endl;
That way you add a newline after each string during output. But if so, then you don't need to manually add a \n character to empty strings during reading.
In other words, decide what is it you want to do. At this time it is not clear.
If you want to restore the discarded
newline characters during reading,
you have to do it for all lines,
not just for empty ones.
If you want to add the newline
characters during output, you don't
need to explictly push them into the
read lines at all.
In fact, it is a rather strange idea to literally push the newline characters into your strings. What for? Since you already read and store your text line-by-line, the newline characters can be implied. I.e. you can do the printing as I do it above (with endl), and everything will look as expected.
I think the simple answer here, is that getline() strips the trailing newline whether or not there is content in the string. So the three reads you do are as follows:
"Line 1"
""
"Line 3"
which you transform into:
"Line 1"
"\n"
"Line 3"
which when printed is:
Line 1
Line 3
I'd use something like this:
std::vector<std::string> text;
std::string str;
while (std::getline(infile, str))
text.push_back(str);
std::copy(text.begin(), text.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
You're adding complexity that stops your code from working.