Categories
javascript numbers validation

Validate decimal numbers in JavaScript – IsNumeric()

2519

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:

01. IsNumeric('-1')      => true
02. IsNumeric('-1.5')    => true
03. IsNumeric('0')       => true
04. IsNumeric('0.42')    => true
05. IsNumeric('.42')     => true
06. IsNumeric('99,999')  => false
07. IsNumeric('0x89f')   => false
08. IsNumeric('#abcdef') => false
09. IsNumeric('1.2.3')   => false
10. IsNumeric('')        => false
11. IsNumeric('blah')    => false

9

  • 268

    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

    Aug 20, 2008 at 14:31

  • 5

    Also check out this post and the great comments.

    – powtac

    Nov 23, 2009 at 18:05


  • 82

    Decimal comma is the standard in entire Europe and Russia (except UK)

    – Calmarius

    Feb 16, 2011 at 14:29

  • 92

    jQuery 1.7 has introduced the jQuery.isNumeric utility function: api.jquery.com/jQuery.isNumeric

    Nov 16, 2011 at 20:04

  • 25

    jQuery.isNumeric will fail the OP’s seventh test case (IsNumeric('0x89f') => *false*). I’m not sure if I agree with this test case, however.

    Aug 27, 2012 at 16:42

2970

@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 of 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 assumptions, 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 isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

P.S. isNaN & isFinite have a confusing behavior due to forced conversion to number. In ES6, Number.isNaN & Number.isFinite would fix these issues. Keep that in mind when using them.


Update :
Here’s how jQuery does it now (2.2-stable):

isNumeric: function(obj) {
    var realStringObj = obj && obj.toString();
    return !jQuery.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
}

Update :
Angular 4.3:

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}

1

  • jsBench says, angulars isNumeric is 0.51% faster than the isNaN && isFinite function. Can somebody confirm that? Cannot share my test without register…

    – aProgger

    Dec 5, 2021 at 12:26

354

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 regular expression.

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

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

Here’s how it works:

The (input - 0) expression forces JavaScript to do type coercion on your input value; it must first be interpreted as a number for the subtraction operation. If that conversion to a number fails, the expression will result in NaN. This numeric result is then compared to the original value you passed in. Since the left hand side is now numeric, type coercion is again used. Now that the input from both sides was coerced to the same type from the same original value, you would think they should always be the same (always true). However, 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 (and only values that cannot be converted to numbers) will result in false.

The check on the length is for a special case involving empty strings. Also 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.

In summary, if you want to know if a value can be converted to a number, actually try to convert it to a number.


I went back and did some research for why a whitespace string did not have the expected output, and I think I get it now: an empty string is coerced to 0 rather than NaN. Simply trimming the string before the length check will handle this case.

Running the unit tests against the new code and it only fails on the infinity and boolean literals, and the only time that should be a problem is if you’re generating code (really, who would type in a literal and check if it’s numeric? You should know), and that would be some strange code to generate.

But, again, the only reason ever to use this is if for some reason you have to avoid isNaN().

0

    84

    This way seems to work well:

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

    In one line:

    const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);
    

    And to test it:

    const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);
        
        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;
        }
    
    console.log(TestIsNumeric());
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    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
    

    0