There are a number of ways you could do this. The method you've tried doesn't work because there is no number-like thing sitting at the read position in the stream. So the input will fail, and the stream's fail-bit will be set. You'll loop forever because you're only testing for eof. Read this for more information.
A simple way is to read a line at a time, and search for the first number by exploiting the second argument to std::strtol
:
#include <iostream>
#include <string>
#include <experimental/optional>
std::experimental::optional<int> find_int_strtol( const std::string & s )
{
for( const char *p = s.c_str(); *p != '\0'; p++ )
{
char *next;
int value = std::strtol( p, &next, 10 );
if( next != p ) {
return value;
}
}
return {};
}
int main()
{
for( std::string line; std::getline( std::cin, line ); )
{
auto n = find_int_strtol( line );
if( n )
{
std::cout << "Got " << n.value() << " in " << line << std::endl;
}
}
return 0;
}
This is a bit clunky and it will also detect negatives, which you might not want. But it's a simple approach. The next
pointer will be different to p
if any characters were extracted. Otherwise the function fails. Then you increment p
by 1 and search again. It looks like a polynomial search, but it's linear.
I've used std::optional
from C++17, but I was testing on a C++14 compiler. It's for convenience. You could write the function without it.
Live example is here.
A more flexible way to solve problems like this is to use a regular expression. In this case, a simple numeric regex search is all you need. The following will only find positive integers, but you can use this type of pattern to find complex data too. Don't forget to include the header <regex>
:
std::experimental::optional<int> find_int_regex( const std::string & s )
{
static const std::regex r( "(\\d+)" );
std::smatch match;
if( std::regex_search( s.begin(), s.end(), match, r ) )
{
return std::stoi( match[1] );
}
return {};
}
Live example is here.