Misbehavior with istringstream conversions

69 views Asked by At

When I try to extract valid numbers from an input using istringstream I get the follwoing misbehavior from istringstream:
For Example:

void extract(void)
{
double x;
string line, temp;

getline(cin, line);
istringstream is(line);
while(is >>temp)
{
    if(istringstream(temp) >>x)
        {std::cout<<"number read: "<<x<<endl;}
}

}

Input: 1 2 3rd 4th

Output:

number read: 1
number read: 2
number read: 3
number read: 4

The misbehavior is istringstream converting the string 3rd to the number 3.
Why does istringstream do this and how can one avoid this?

2

There are 2 answers

3
Some programmer dude On BEST ANSWER

It's because you read numbers from the stream.

The >> operator extracts "3rd" from the stream, and tries to convert it to a double, but since only the first character of the string is a number, it can only parse the "3" and simply discard the non-digit characters.

If you want "3rd" then you need to read it as a string.

0
James Kanze On

The >> operators only read as much as they can in the stream, leaving any remaining characters. Thus:

std::istringstream( temp ) >> x

will only extract the 3 if temp contains 3rd, leaving the rd. In order to ensure that the entire field has been read, you need to ensure that you are at the end:

std::istringstream fieldParser( temp );
if ( fieldParser >> x && fieldParser.peek() == EOF ) {
    // ...
}

for example. (More generally, you'll want to append a >> std::ws to the end of the input chain, to skip any trailing white space. In your case, however, since you get temp using the >> operator, you're guaranteed that it contains no white space.)

FWIW: in this particualar case, I'd use strtod:

errno = 0;
const char* end;
x = strtod( temp.c_str(), &end );
if ( errno != 0 || *end != '\0' ) {
    //  Error occured...
}

Either way, however, you can't do it in a single if; you'll need extra code before.