views:

65157

answers:

15

What's the cleanest, most effective way to validate decimal numbers in JavaScript?

Bonus points for:

  1. Clarity. Solution should be clean and simple.
  2. Cross-platform.

Test cases:

 1. IsNumeric('-1') => true
 2. IsNumeric('-1.5') => true
 3. IsNumeric('0') => true
 4. IsNumeric('0.42') => true
 5. Isnumeric('.42') => true
 6. IsNUmeric('99,999') => *false*
 7. IsNumeric('0x89f') => *false*
 8. IsNumeric('#abcdef')=> *false*
 9. IsNumeric('1.2.3') => *false*
 10. IsNumeric('') => *false*
 11. IsNumeric('blah') => *false*
+3  A: 

This way seems to work well:

function IsNumeric(input){
    var RE = /^-{0,1}\d*\.{0,1}\d+$/;
    return (RE.test(input));
}

And to test it:

// alert(TestIsNumeric());

function TestIsNumeric(){
    var results = ''
    results += (IsNumeric('-1')?"Pass":"Fail") + ": IsNumeric('-1') => true\n";
    results += (IsNumeric('-1.5')?"Pass":"Fail") + ": IsNumeric('-1.5') => true\n";
    results += (IsNumeric('0')?"Pass":"Fail") + ": IsNumeric('0') => true\n";
    results += (IsNumeric('0.42')?"Pass":"Fail") + ": IsNumeric('0.42') => true\n";
    results += (IsNumeric('.42')?"Pass":"Fail") + ": IsNumeric('.42') => true\n";
    results += (!IsNumeric('99,999')?"Pass":"Fail") + ": IsNumeric('99,999') => false\n";
    results += (!IsNumeric('0x89f')?"Pass":"Fail") + ": IsNumeric('0x89f') => false\n";
    results += (!IsNumeric('#abcdef')?"Pass":"Fail") + ": IsNumeric('#abcdef') => false\n";
    results += (!IsNumeric('1.2.3')?"Pass":"Fail") + ": IsNumeric('1.2.3') => false\n";
    results += (!IsNumeric('')?"Pass":"Fail") + ": IsNumeric('') => false\n";
    results += (!IsNumeric('blah')?"Pass":"Fail") + ": IsNumeric('blah') => false\n";

    return results;
}

I borrowed that regex from http://www.codetoad.com/javascript/isnumeric.asp. Explanation:

/^ match beginning of string
-{0,1} optional negative sign
\d* optional digits
\.{0,1} optional decimal point
\d+ at least one digit
$/ match end of string
Michael Haren
//ALSO SHOULD BE ADDED TO YOUR TEST results += (!IsNumeric('-')?"Pass":"Fail") + ": IsNumeric('-') => false\n"; results += (!IsNumeric('01')?"Pass":"Fail") + ": IsNumeric('01') => false\n"; results += (!IsNumeric('-01')?"Pass":"Fail") + ": IsNumeric('-01') => false\n"; results += (!IsNumeric('000')?"Pass":"Fail") + ": IsNumeric('000') => false\n";
Dan
+8  A: 

Just a note 99,999 is a valid number in France, its the same as 99.999 in uk/ us format, so if you are reading in a string from say an input form then 99,999 may be true.

Re0sless
A: 

For matches in scientific notation...

/^-?\d*\.?\d+([eE]\d*.\d+)?$/
nlucaroni
A: 

A couple tests to add:

IsNumeric('01.05') => false
IsNumeric('1.') => false
IsNumeric('.') => false

I came up with this:

function IsNumeric(input){
  return /^-?(0|[1-9]\d*|(?=\.))(\.\d+)?$/.test(input);
}

The solution has:

  • An optional negative sign at the beginning
  • A single zero, or one or more digits not starting with 0, or nothing so long as a period follows
  • If a period exists, that it's followed by 1 or more numbers
pottedmeat
A: 
Marius
+3  A: 

Can't you use the function isNaN? I believe if you test !isNaN(yourstringhere) works fine for any of these situations.

bubbassauro
Note: !isNaN(null) == true since Number(null) == 0
Jonathan Lonowski
if (!(x==null || isNaN(x))) alert("isNumeric"); // But this solution accepts 0x40 so it is still not what the op wanted.
some
Note that isNaN("Infinity") === false, which is probably also not what you want (but also won't happen in real life).
Erik Hesselink
+2  A: 

Yeah, the built-in isNaN(object) will be much faster than any regex parsing, because it's built-in and compiled, instead of interpreted on the fly.

Although the results are somewhat different to what you're looking for (try it):

document.write(!isNaN('-1') + "<br />");
document.write(!isNaN('-1.5') + "<br />");
document.write(!isNaN('0') + "<br />");
document.write(!isNaN('0.42') + "<br />");
document.write(!isNaN('.42') + "<br />");
document.write(!isNaN('99,999') + "<br />");
document.write(!isNaN('0x89f') + "<br />");
document.write(!isNaN('#abcdef') + "<br />");
document.write(!isNaN('1.2.3') + "<br />");
document.write(!isNaN('') + "<br />");
document.write(!isNaN('blah') + "<br />");

true
true
true
true
true
false
true
false
false
true
false
travis
A: 

It can be done without RegExp as

function IsNumeric(data){
    return parseFloat(data)==data;
}
Aquatic
shouldnt it ===
powtac
If we are using == , it will return true even for numbers presented as strings. So the "42" will be counted as valid number in case of "==" and will be counted as invalid in case of ===
Aquatic
+77  A: 

Arrrgh! Don't listen to the regular expression answers. RegEx is icky for this, and I'm not talking just performance. It's so easy to make subtle, impossible to spot mistakes with your regex.

If you can't use isNaN(), this should work much better:

function IsNumeric(input)
{
   return (input - 0) == input && input.length > 0;
}

The (input - 0) expression forces javascript to do type coercion on your input value; it must first be interpreted as a number for the boolean compare. If that conversion to a number fails, the expression will result in NaN. Then this numeric result is compared to the original value you passed in. Since the left hand side is a number, type coercion is again used. They should always be the same (always true), but there's a special rule that says NaN is never equal to NaN, and so a value that can't be converted to a number will always return false. The check on the length is of course for the empty string special case. In summary, if you want to know if a value can be converted to a number, actually try to convert it to a number.

Note that it falls down on your 0x89f test, but that's because in many environments that's an okay way to define a number literal. If you want to catch that specific scenario you could add an additional check. Even better, if that's your reason for not using isNaN() then just wrap your own function around isNaN() that can also do the additional check.

Joel Coehoorn
even better if you just need to account for the 0x89f special case is wrap an IsNumeric() function around isNaN() that then makes your special check only if isNaN() returns false.
Joel Coehoorn
Update: promoted my earlier comment to become part of the answer.
Joel Coehoorn
This fails on whitespace strings, eg `IsNumeric(' ')`, `IsNumeric('\n\t')`, etc all return `true`
Crescent Fresh
It will also fail on `Number` literals `IsNumeric(5) == false;` check the set of unit tests I posted, this function is the number `16` on the test suite. http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844
CMS
Perfect! Thanks for sharing..
tbaskan
+2  A: 

YUI uses this:

...
isNumber: function(o) {
    return typeof o === 'number' && isFinite(o);
}
...
camomileCase
A: 
function IsNumeric(num) {
     return (num >=0 || num < 0);

}

This works for 0x23 type numbers as well.

Derrick
+1  A: 

Note that

return isNaN(parseInt(expression))

return isNaN(parseFloat(expression))

ARE BUGGY !!!!!!!!!!!!!!!!!!!

parseInt("00a12") => 0

parseFloat("0.2zzzzz") => 0.2

Dan
A: 

Also check out this post and the great comments: http://debuggable.com/posts/7+8===7-in-javascript%3A4acba016-d204-489b-b5a0-1fd0cbdd56cb

powtac
+45  A: 

@Joel's answer is pretty close, but it will fail in the following cases:

// Whitespace strings:
IsNumeric(' ') == true;
IsNumeric('\t\t') == true;
IsNumeric('\n\r') == true;

// Number literals:
IsNumeric(-1) == false;
IsNumeric(0) == false;
IsNumeric(1.1) == false;
IsNumeric(8e5) == false;

Some time ago I had to implement an IsNumeric function, to find out if a variable contained a numeric value, regardless its type, it could be a String containing a numeric value (I had to consider also exponential notation, etc.), a Number object, virtually anything could be passed to that function, I couldn't make any type assumption, taking care of type coercion (eg. +true == 1; but true shouldn't be considered as "numeric").

I think is worth sharing this set of +30 unit tests made to numerous function implementations, and also share the one that passes all my tests:

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}
CMS
Great answer, thanks for sharing the tests too.
barfoon
perfect, just what i was after
sleep-er
+1  A: 

To me, this is the best way:

isNumber : function(v){
   return typeof v === 'number' && isFinite(v);
}
InsertNameHere