HiveBrain v1.2.0
Get Started
← Back to all entries
debugcMinor

Test if string is numeric

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stringtestnumeric

Problem

I want to implement the following function:

// Return true if and only if 's' is numeric including
// leading positive/negative sign, decimal point.
bool isnumeric( const char * s );


It is somewhat similar to strtol() but I don't need to return the number.

My approach is to count various things unless I can bail out:

bool isnumeric( char const * str ) {
  if( !str ) { return false; }
  int signs = 0;
  int decimals = 0;
  int digits = 0;
  int digitsAfterDecimal = 0;

  for( char const * p = str; *p; ++p ) {

    if( (*p == '+') || (*p == '-') ) {
      if( (decimals > 0) || (digits > 0) ) { return false; }
      signs += 1;
      if( signs == 2 ) { return false; }
    }
    else if( *p == '.' ) {
      decimals += 1;
      if( decimals == 2 ) { return false; }
    }
    else if( ! isdigit( *p ) ) { 
      return false;
    }
    else {
      digits += 1;
      if( decimals > 0 ) {
        digitsAfterDecimal += 1;
      }
    }
  }
  return (decimals > 0) ? ((digits > 0) && (digitsAfterDecimal > 0))
                        : (digits > 0) ;
}


I also have the following tests:

void test_isnumeric() {
  assert( isnumeric( "42" ) );
  assert( isnumeric( "42.0" ) );
  assert( isnumeric( "42.56" ) );
  assert( isnumeric( "+42" ) );
  assert( isnumeric( ".42" ) );
  assert( isnumeric( "+.42" ) );

  assert( ! isnumeric( "42." ) );
  assert( ! isnumeric( "++42" ) );
  assert( ! isnumeric( "+." ) );
  assert( ! isnumeric( "4+" ) );
}

int main( void ) {
  test_isnumeric();
}


To make it easy to clone and modify, the full code is available here.

Please comment on design, structuring, test coverage etc. Mentioning failing tests are most welcome.

Solution

State variables are bad. Keep the state explicit, along the lines of:

if (*p == '+' || *p == '-') p++;
if (!isdigit(*p)) return False;
while (isdigit(*p)) p++;
if (*p == 0) return True;
if (*p != '.') return False;
p++;
while (isdigit(*p)) p++;
return *p == 0;


Update: few fixes thanks to Edward

Code Snippets

if (*p == '+' || *p == '-') p++;
if (!isdigit(*p)) return False;
while (isdigit(*p)) p++;
if (*p == 0) return True;
if (*p != '.') return False;
p++;
while (isdigit(*p)) p++;
return *p == 0;

Context

StackExchange Code Review Q#48438, answer score: 4

Revisions (0)

No revisions yet.