Reputation: 795
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?
Upvotes: 1
Views: 69
Reputation: 409176
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.
Upvotes: 3
Reputation: 153919
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.
Upvotes: 0