10

I want to test if a string can be cast as a float. I have been trying to use parseFloat to achieve this.

console.log(!isNaN(parseFloat("10000"))); // should return true
console.log(!isNaN(parseFloat("100T0"))); // should return false (but doesn't)

Turns out that parseFloat just stops reading a string as soon as it hits a character that's not a digit, then returns whatever it has passed over so far. So parseFloat("100T0") actually returns 100 and not NaN.

What's a better js test to see if a string can be cast as a float?

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
rvictordelta
  • 630
  • 2
  • 8
  • 23

5 Answers5

9

There's no one built-in operation provided by default in JavaScript that matches a reasonable "is this string a number" definition (to my mind, anyway). You can get close with Number, unary +, or implicit conversion (just passing the string into isNaN directly), with the caveat that they all do the same thing, which includes considering "" to be 0:

// Number
console.log(!isNaN(Number("10000"))); // true
console.log(!isNaN(Number("100T0"))); // false
console.log(!isNaN(Number("")));      // true (!)

// Same as implicit (here triggered with a unary +)
console.log(!isNaN(+"10000")); // true
console.log(!isNaN(+"100T0")); // false
console.log(!isNaN(+""));      // true (!)


// Same as implicit
console.log(!isNaN("10000")); // true
console.log(!isNaN("100T0")); // false
console.log(!isNaN(""));      // true (!)

My answer to a related question goes into your options in detail.

Consequently, you can either do a regular expression (be sure to allow for scientific notation!) or a check for "" up-front:

function toNumber(str) {
  str = String(str).trim();
  return !str ? NaN : Number(str);
}
console.log(!isNaN(toNumber("10000"))); // true
console.log(!isNaN(toNumber("100T0"))); // false
console.log(!isNaN(toNumber("")));      // false
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
9

You won't get what you expect with parseFloat(), because it tries to parse 100T0 and returns 100, so it's a valid Number.

Instead of using isNaN() you can just use regex, to check if the given string is only composed of numbers.

This is the regex /^\-?[0-9]+(e[0-9]+)?(\.[0-9]+)?$/ you need, and this is how should be your code:

function isItNumber(str) {
  return /^\-?[0-9]+(e[0-9]+)?(\.[0-9]+)?$/.test(str);
}

Demo:

function isItNumber(str) {
  return /^\-?[0-9]+(e[0-9]+)?(\.[0-9]+)?$/.test(str);
}

console.log(isItNumber("10000")) // should return true
console.log(isItNumber("100T0"))
console.log(isItNumber("10e5"))
console.log(isItNumber("100.50"))
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
3

You could try with a regular expresion:

> (/^-?[\d]*(\.[\d]+)?$/g).test('0');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('1000');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('10E0');
false
> (/^-?[\d]*(\.[\d]+)?$/g).test('1000.E');
false
> (/^-?[\d]*(\.[\d]+)?$/g).test('1000.1');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('1.1000');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('.1000');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('1000.');
false
> (/^-?[\d]*(\.[\d]+)?$/g).test('-.1');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('-1000.1');
true
> (/^-?[\d]*(\.[\d]+)?$/g).test('-1000');
true

With a function:

function isValidFloat(str) {
    return (/^-?[\d]*(\.[\d]+)?$/g).test(str);
}
Exos
  • 3,958
  • 2
  • 22
  • 30
0

Another idea in psuedocode

1) Loop through string substrings (imitating parseFloat)
2) Get the substring that parseFloat stops at
3) Compare this substring to the original

Old psuedocode - does not work totally - maybe with modifications

What you can do is this (psuedocode)

if (parseFloat (value)).toString() <> value then
   you know that the parse float only converted part of the value

Basically you are saying that string > float > (back to) string should give the same string if the conversations work "correctly".

Hassan Voyeau
  • 3,383
  • 4
  • 22
  • 24
0

You can try a regex to match only float format strings. Hope this helps.

const reg = /^-?([0-9]+\.[0-9]+)$/g;

console.log("Should match");
console.log("123.2".match(reg));
console.log("12.000".match(reg));
console.log("-12.000".match(reg));

console.log("Should not match");
console.log("123".match(reg));
console.log("123a123".match(reg));
console.log("1e2".match(reg));
Alex G
  • 1,897
  • 2
  • 10
  • 15