(Built-in) way in JavaScript to check if a string is a valid number

(Built-in) way in JavaScript to check if a string is a valid number

I’m hoping there’s something in the same conceptual space as the old VB6 IsNumeric() function?

Solutions/Answers:

Solution 1:

To check if a variable (including a string) is a number, check if it is not a number:

This works regardless of whether the variable content is a string or number.

isNaN(num)         // returns true if the variable does NOT contain a valid number

Examples

isNaN(123)         // false
isNaN('123')       // false
isNaN('1e10000')   // false (This translates to Infinity, which is a number)
isNaN('foo')       // true
isNaN('10px')      // true

Of course, you can negate this if you need to. For example, to implement the IsNumeric example you gave:

function isNumeric(num){
  return !isNaN(num)
}

To convert a string containing a number into a number:

Only works if the string only contains numeric characters, else it returns NaN.

+num               // returns the numeric value of the string, or NaN 
                   // if the string isn't purely numeric characters

Examples

+'12'              // 12
+'12.'             // 12
+'12..'            // Nan
+'.12'             // 0.12
+'..12'            // Nan
+'foo'             // NaN
+'12px'            // NaN

To convert a string loosely to a number

Useful for converting ’12px’ to 12, for example:

parseInt(num)      // extracts a numeric value from the 
                   // start of the string, or NaN.

Examples

parseInt('12')     // 12
parseInt('aaa')    // NaN
parseInt('12px')   // 12
parseInt('foo2')   // NaN      These last two may be different
parseInt('12a5')   // 12       from what you expected to see. 

Floats

Bear in mind that, unlike +num, parseInt (as the name suggests) will convert a float into an integer by chopping off everything following the decimal point (if you want to use parseInt() because of this behaviour, you’re probably better off using another method instead):

+'12.345'          // 12.345
parseInt(12.345)   // 12
parseInt('12.345') // 12

Empty strings

Empty strings may be a little counter-intuitive. +num converts empty strings to zero, and isNaN() assumes the same:

+''                // 0
isNaN('')          // false

But parseInt() does not agree:

parseInt('')       // NaN

Solution 2:

And you could go the RegExp-way:

var num = "987238";

if(num.match(/^-{0,1}\d+$/)){
  //valid integer (positive or negative)
}else if(num.match(/^\d+\.\d+$/)){
  //valid float
}else{
  //not valid number
}

Solution 3:

If you’re just trying to check if a string is a whole number (no decimal places), regex is a good way to go. Other methods such as isNaN are too complicated for something so simple.

function isNumeric(value) {
    return /^-{0,1}\d+$/.test(value);
}

console.log(isNumeric('abcd'));         // false
console.log(isNumeric('123a'));         // false
console.log(isNumeric('1'));            // true
console.log(isNumeric('1234567890'));   // true
console.log(isNumeric('-23'));          // true
console.log(isNumeric(1234));           // true
console.log(isNumeric('123.4'));        // false
console.log(isNumeric(''));             // false
console.log(isNumeric(undefined));      // false
console.log(isNumeric(null));           // false

To only allow positive whole numbers use this:

function isNumeric(value) {
    return /^\d+$/.test(value);
}

console.log(isNumeric('123'));          // true
console.log(isNumeric('-23'));          // false

Solution 4:

If you really want to make sure that a string contains only a number, any number (integer or floating point), and exactly a number, you cannot use parseInt()/ parseFloat(), Number(), or !isNaN() by themselves. Note that !isNaN() is actually returning true when Number() would return a number, and false when it would return NaN, so I will exclude it from the rest of the discussion.

The problem with parseFloat() is that it will return a number if the string contains any number, even if the string doesn’t contain only and exactly a number:

parseFloat("2016-12-31")  // returns 2016
parseFloat("1-1") // return 1
parseFloat("1.2.3") // returns 1.2

The problem with Number() is that it will return a number in cases where the passed value is not a number at all!

Number("") // returns 0
Number(" ") // returns 0
Number(" \u00A0   \t\n\r") // returns 0

The problem with rolling your own regex is that unless you create the exact regex for matching a floating point number as Javascript recognizes it you are going to miss cases or recognize cases where you shouldn’t. And even if you can roll your own regex, why? There are simpler built-in ways to do it.

However, it turns out that Number() (and isNaN()) does the right thing for every case where parseFloat() returns a number when it shouldn’t, and vice versa. So to find out if a string is really exactly and only a number, call both functions and see if they both return true:

function isNumber(str) {
  if (typeof str != "string") return false // we only process strings!
  // could also coerce to string: str = ""+str
  return !isNaN(str) && !isNaN(parseFloat(str))
}

Solution 5:

Try the isNan function:

The isNaN() function determines whether a value is an illegal number (Not-a-Number).

This function returns true if the value equates to NaN. Otherwise it returns false.

This function is different from the Number specific Number.isNaN() method.

  The global isNaN() function, converts the tested value to a Number, then tests it.

Number.isNan() does not convert the values to a Number, and will not return true for any value that is not of the type Number…

Solution 6:

Old question, but there are several points missing in the given answers.

Scientific notation.

!isNaN('1e+30') is true, however in most of the cases when people ask for numbers, they do not want to match things like 1e+30.

Large floating numbers may behave weird

Observe (using Node.js):

> var s = Array(16 + 1).join('9')
undefined
> s.length
16
> s
'9999999999999999'
> !isNaN(s)
true
> Number(s)
10000000000000000
> String(Number(s)) === s
false
>

On the other hand:

> var s = Array(16 + 1).join('1')
undefined
> String(Number(s)) === s
true
> var s = Array(15 + 1).join('9')
undefined
> String(Number(s)) === s
true
>

So, if one expects String(Number(s)) === s, then better limit your strings to 15 digits at most (after omitting leading zeros).

Infinity

> typeof Infinity
'number'
> !isNaN('Infinity')
true
> isFinite('Infinity')
false
>

Given all that, checking that the given string is a number satisfying all of the following:

  • non scientific notation
  • predictable conversion to Number and back to String
  • finite

is not such an easy task. Here is a simple version:

  function isNonScientificNumberString(o) {
    if (!o || typeof o !== 'string') {
      // Should not be given anything but strings.
      return false;
    }
    return o.length <= 15 && o.indexOf('e+') < 0 && o.indexOf('E+') < 0 && !isNaN(o) && isFinite(o);
  }

However, even this one is far from complete. Leading zeros are not handled here, but they do screw the length test.