Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert an entire String into an Integer in JavaScript

I recently ran into a piece of code very much like this one:

var nHours = parseInt(txtHours);
if( isNaN(nHours))  // Do something
else // Do something else with the value

The developer who wrote this code was under the impression that nHours would either be an integer that exactly matched txtHours or NaN. There are several things wrong with this assumption.

First, the developer left of the radix argument which means input of "09" would result in a value of 0 instead of 9. This issue can be resolved by adding the radix in like so:

var nHours = parseInt(txtHours,10);
if( isNaN(nHours))  // Do something
else // Do something else with the value

Next, input of "1.5" will result in a value of 1 instead of NaN which is not what the developer expected since 1.5 is not an integer. Likewise a value of "1a" will result in a value of 1 instead of NaN.

All of these issues are somewhat understandable since this is one of the most common examples of how to convert a string to an integer and most places don't discuss these cases.

At any rate it got me thinking that I'm not aware of any built in way to get an integer like this. There is Number(txtHours) (or +txtHours) which comes closer but accepts non-integer numbers and will treat null and "" as 0 instead of NaN.

To help the developer out I provided the following function:

function ConvertToInteger(text)
{
    var number = Math.floor(+text);
    return text && number == text ? number : NaN;
}

This seems to cover all the above issues. Does anyone know of anything wrong with this technique or maybe a simpler way to get the same results?

like image 619
drs9222 Avatar asked Nov 12 '10 19:11

drs9222


2 Answers

Here, that's what I came up with:

function integer(x) {
    if (typeof x !== "number" && typeof x !== "string" || x === "") {
        return NaN;
    } else {
        x = Number(x);
        return x === Math.floor(x) ? x : NaN;
    }
}

(Note: I updated this function to saveguard against white-space strings. See below.)

The idea is to only accept arguments which type is either Number or String (but not the empty string value). Then a conversion to Number is done (in case it was a string), and finally its value is compared to the floor() value to determine if the number is a integer or not.

integer(); // NaN
integer(""); // NaN
integer(null); // NaN
integer(true); // NaN
integer(false); // NaN
integer("1a"); // NaN
integer("1.3"); // NaN
integer(1.3); // NaN    
integer(7); // 7

However, the NaN value is "misused" here, since floats and strings representing floats result in NaN, and that is technically not true.

Also, note that because of the way strings are converted into numbers, the string argument may have trailing or leading white-space, or leading zeroes:

integer("   3   "); // 3    
integer("0003"); // 3

Another approach...

You can use a regular expression if the input value is a string. This regexp: /^\s*(\+|-)?\d+\s*$/ will match strings that represent integers.

UPDATED FUNCTION!

function integer(x) {
    if ( typeof x === "string" && /^\s*(\+|-)?\d+\s*$/.test(x) ) {
        x = Number(x);
    }
    if ( typeof x === "number" ) {
        return x === Math.floor(x) ? x : NaN;
    }
    return NaN;
}

This version of integer() is more strict as it allows only strings that follow a certain pattern (which is tested with a regexp). It produces the same results as the other integer() function, except that it additionally disregards all white-space strings (as pointed out by @CMS).

Updated again!

I noticed @Zecc's answer and simplified the code a bit... I guess this works, too:

function integer(x) {
    if( /^\s*(\+|-)?\d+\s*$/.test(String(x)) ){
        return parseInt(x, 10);
    }
    return Number.NaN;
}  

It probaly isn't the fastest solution (in terms of performance), but I like its simplicity :)

like image 131
Šime Vidas Avatar answered Sep 29 '22 14:09

Šime Vidas


Here's my attempt:

function integer(x) {
    var n = parseFloat(x); // No need to check typeof x; parseFloat does it for us
    if(!isNaN(n) && /^\s*(\+|-)?\d+\s*$/.test(String(x))){
        return n;
    }
    return Number.NaN;
}

I have to credit Šime Vidas for the regex, though I would get there myself.

Edit: I wasn't aware there was a NaN global. I've always used Number.NaN.
Live and learn.

like image 24
Zecc Avatar answered Sep 29 '22 14:09

Zecc