Find the first non-digit in a string…
size_t FirstNonDigit( const char* s )
{
site_t i;
for( i = 0; i < strlen( s ); ++i )
{
if( !isdigit( s[i] ) )
break;
}
return i == strlen(s) ? (size_t)-1 : i;
}
Excellent... but old fashioned.
We really want to use iterator style code and while we're at it, lets use the C++ locale facilities and not the old fashioned C isxxx functions.
const char* FirstNonDigit( const char* s, const char* e )
{
const std::locale& classic = std::locale::classic();
for( ; s != e; ++s )
{
if( !std::isdigit( *s, classic ) )
break;
}
return s;
}
Much more modern!
But wait, a manually rolled for loop? Surely this is a job for std::find_if.
namespace
{
struct IsNonDigit
{
bool operator()(char c)
{
return !std::isdigit( c, std::locale::classic() );
}
};
}
const char* FirstNonDigit( const char* s, const char* e )
{
return std::find_if( s, e, IsNonDigit() );
}
Excellent, we managed to make that function body really simple... but we seemed to have sprouted an extra class.
We're not doing anything that exotic, perhaps we can just used some standard functions?
// Does not work
const char* FirstNonDigit( const char* s, const char* e )
{
return std::find_if( s, e, std::not1( std::bind2nd(
std::isdigit< char >, std::locale::classic() ) ) );
}
Unfortunately, this doesn't work as std::bind2nd ends up trying to create a refence to a reference.
Luckily tr1 can come to our rescue... the bind here is that tr1::bind returns a function object that isn't derived from std::unary_function, so we can't pass it straight to std::not1, we have to bind it to std::logical_not.
const char* FirstNonDigit( const char* s, const char* e )
{
return std::find_if( s, e, std::tr1::bind( std::logical_not< bool >(),
std::tr1::bind( std::isdigit< char >, std::tr1::placeholders::_1,
std::locale::classic() ) ) );
}
Excellent, it's a one liner!