check if string is numeric

Can't get this to work..

String str = "+1.1234";
isnan(str.toFloat()) ; -> FALSE

String str = "-------";
isnan(str.toFloat()) ; -> FALSE (shuold return TRUE, since it is NOT A number)

Always returns FALSE, since str.toFloat() returns 0.00 for non numeric values.

So, what's the alternatives? I need to check if a string is numeric or not.
Also tried .toInt() with the same result.

any suggestions?

isNan() is not what you want. That only checks to see if it is the special value you get when a math operation goes bad like dividing by zero.

include ctype.h and use isdigit() on all the characters in the string. If one of them is a digit, you have a number.

KeithRB:
isNan() is not what you want. That only checks to see if it is the special value you get when a math operation goes bad like dividing by zero.

include ctype.h and use isdigit() on all the characters in the string. If one of them is a digit, you have a number.

Great thanx..
That works...

i did a isDigit(str.charAt(2)) -> TRUE

As long as you are sure that the 3rd character is always a number... decimal point is not a digit!

use isdigit() on all the characters in the string. If one of them is a digit, you have a number.

That doesn't sound right. By that reasoning the string AAA3ZZZ would be a number because one of the characters in the string is a digit.

It is the simplest solution. The real one is much harder. It works for his two test cases, which is all I am asked to do as a programmer. 8^)

Keith is right… For my examples, that works just fine. And i know that digit 2 must be an integer (since char 1 is oa + or - sign)

This function should work for all purposes:

boolean isValidNumber(String str){
for(byte i=0;i<str.length();i++)
{
if(isDigit(str.charAt(i))) return true;
}
return false;
}

Just for completeness:

read character c:
If c is whitespace: get next character
if c is +, - or . (decimal point): get next character
if c is digit: stop it is a number
if c is something else: stop it is not a number
if there are no more characters: stop, it is not a number

hbx2013:
Keith is right… For my examples, that works just fine. And i know that digit 2 must be an integer (since char 1 is oa + or - sign)

This function should work for all purposes:

boolean isValidNumber(String str){
for(byte i=0;i<str.length();i++)
{
if(isDigit(str.charAt(i))) return true;
}
return false;
}

I just realized that my function will not work on UKHeliBobs example.

this may work better:

boolean isValidNumber(String str){
boolean isNum=false;
for(byte i=0;i<str.length();i++)
{
isNum = isDigit(str.charAt(i)) || str.charAt(i) == ‘+’ || str.charAt(i) == ‘.’ || str.charAt(i) == ‘-’;
if(!isNum) return false;
}
return isNum;
}

I suppose you could use atof() although the 0.0 return value seems ambiguous. You could validate the string before the conversion if you like - it would be a relatively simple parsing job, or you could use a regular expression to do it (I seem to remember somebody posted a regex library for Arduino recently).

PeterH:
I suppose you could use atof() although the 0.0 return value seems ambiguous. You could validate the string before the conversion if you like - it would be a relatively simple parsing job, or you could use a regular expression to do it (I seem to remember somebody posted a regex library for Arduino recently).

The problem here is not the conversion, but the validation.
.toFloat() is working just fine on 1.5.5. But i think it should return a "NAN" or similiar if the input is not a valid number-(in string).

I normally don’t use the String data type, but this works. Only one ‘+’ or ‘-’ allowed at first character, and only one decimal point.

void setup() {
  Serial.begin(9600);

  if(isFloat("+123.45")) Serial.println("+123.45 ok");
  else Serial.println("+123.45 failed");  

  if(isFloat("+123.4.5")) Serial.println("+123.4.5 ok");
  else Serial.println("+123.4.5 failed");  

  if(isFloat("+12A.45")) Serial.println("+12A.45 ok");
  else Serial.println("+12A.45 failed");  

  if(isFloat("123.45")) Serial.println("123.45 ok");
  else Serial.println("123.45 failed");  

  if(isFloat("-123.45")) Serial.println("-123.45 ok");
  else Serial.println("-123.45 failed");  

  if(isFloat("-1+23.45")) Serial.println("-1+23.45 ok");
  else Serial.println("-1+23.45 failed");  
}

void loop() {
}

boolean isFloat(String tString) {
  String tBuf;
  boolean decPt = false;
  
  if(tString.charAt(0) == '+' || tString.charAt(0) == '-') tBuf = &tString[1];
  else tBuf = tString;  

  for(int x=0;x<tBuf.length();x++)
  {
    if(tBuf.charAt(x) == '.') {
      if(decPt) return false;
      else decPt = true;  
    }    
    else if(tBuf.charAt(x) < '0' || tBuf.charAt(x) > '9') return false;
  }
  return true;
}

I get this result:

+123.45 ok
+123.4.5 failed
+12A.45 failed
123.45 ok
-123.45 ok
-1+23.45 failed

1 Like

SurferTim:
I normally don’t use the String data type, but this works. Only one ‘+’ or ‘-’ allowed at first character, and only one decimal point.

void setup() {

Serial.begin(9600);

if(isFloat("+123.45")) Serial.println("+123.45 ok");
  else Serial.println("+123.45 failed");

if(isFloat("+123.4.5")) Serial.println("+123.4.5 ok");
  else Serial.println("+123.4.5 failed");

if(isFloat("+12A.45")) Serial.println("+12A.45 ok");
  else Serial.println("+12A.45 failed");

if(isFloat(“123.45”)) Serial.println(“123.45 ok”);
  else Serial.println(“123.45 failed”);

if(isFloat("-123.45")) Serial.println("-123.45 ok");
  else Serial.println("-123.45 failed");

if(isFloat("-1+23.45")) Serial.println("-1+23.45 ok");
  else Serial.println("-1+23.45 failed"); 
}

void loop() {
}

boolean isFloat(String tString) {
  String tBuf;
  boolean decPt = false;
 
  if(tString.charAt(0) == ‘+’ || tString.charAt(0) == ‘-’) tBuf = &tString[1];
  else tBuf = tString;

for(int x=0;x<tBuf.length();x++)
  {
    if(tBuf.charAt(x) == ‘.’) {
      if(decPt) return false;
      else decPt = true; 
    }   
    else if(tBuf.charAt(x) < ‘0’ || tBuf.charAt(x) > ‘9’) return false;
  }
  return true;
}




I get this result:


> +123.45 ok
> +123.4.5 failed
> +12A.45 failed
> 123.45 ok
> -123.45 ok
> -1+23.45 failed

Thanx Tim…
Your solution reminds alot of my last function:

boolean isValidNumber(String str)
{
boolean isNum=false;
if(!(str.charAt(0) == ‘+’ || str.charAt(0) == ‘-’ || isDigit(str.charAt(0)))) return false;

for(byte i=1;i<str.length();i++)
{
if(!(isDigit(str.charAt(i)) || str.charAt(i) == ‘.’)) return false;
}
return true;
}

There is a good example of reading numbers like this, in the tinygps library.

If you have to do this sort of thing often, you can write your own function.

hbx2013:
Keith is right… For my examples, that works just fine. And i know that digit 2 must be an integer (since char 1 is oa + or - sign)

This function should work for all purposes:

boolean isValidNumber(String str){
for(byte i=0;i<str.length();i++)
{
if(isDigit(str.charAt(i))) return true;
}
return false;
}

What is the source of these strings ?

It is the simplest solution. The real one is much harder. It works for his two test cases, which is all I am asked to do as a programmer. 8^)

It’s a good thing you don’t work for me, then. Programmers are NOT supposed to handle just the identified test cases. They are supposed to anticipate additional test cases.

Checking that all the characters in the String (or string) are ‘-’, ‘.’, >= ‘0’ and <= ‘9’, or ‘e’ or ‘E’ will work for all inputs. Developing a function that tested for strings that are valid as floats would be easy. Developing a function that tested for strings that are valid as ints would be easy. Developing a function that tested for strings that are valid as numbers would be easy. Knowing which function to develop is harder, but not by much.

UKHeliBob:

hbx2013:
Keith is right… For my examples, that works just fine. And i know that digit 2 must be an integer (since char 1 is oa + or - sign)

This function should work for all purposes:

boolean isValidNumber(String str){
for(byte i=0;i<str.length();i++)
{
if(isDigit(str.charAt(i))) return true;
}
return false;
}

What is the source of these strings ?

They’re coming from a gauge-meter, over a BT-link.

What I had in mind was that the strings may be delimited, perhaps by a carriage return/linefeed or some other character. In which case you may be able to be certain that the string you are reading is numeric or not by virtue of its position in the overall string being received. What does the overall string that you receive consist of ?

It's a good thing you don't work for me, then. Programmers are NOT supposed to handle just the identified test cases. They are supposed to anticipate additional test cases.

You did see the smiley, right?

In this case, since we are just looking for a "parseable" number, E's don't matter, since you will not encounter an E before a digit.

In this case, since we are just looking for a "parseable" number, E's don't matter, since you will not encounter an E before a digit.

So, the input will never look like 1.2E+3?

Hmmm, I forgot to deal with the possibility of '+' in a string...