Convert an entire String into an Integer in JavaScript
I recently ran into a piece of code 开发者_JS百科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?
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 :)
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.
My Solution involves some cheap trick. It based on the fact that bit operators in Javascript convert their operands to integers.
I wasn't quite sure if strings representing integers should work so here are two different solutions.
function integer (number) {
return ~~number == number ? ~~number : NaN;
}
function integer (number) {
return ~~number === number ? ~~number : NaN;
}
The first one will work with both integers as strings, the second one won't. The bitwise not (~) operator will convert its operand to an integer. This method fails for integers bigger which can't be represented by the 32bit wide representation of integers (-2147483647 .. 2147483647).
You can first convert a String to an Integer, and then back to a String again. Then check if first and second strings match.
Edit: an example of what I meant:
function cs (stringInt) {
var trimmed = stringInt.trim(); // trim original string
var num = parseInt(trimmed, 10); // convert string to integer
newString = num + ""; // convert newly created integer back to string
console.log(newString); // (works in at least Firefox and Chrome) check what's new string like
return (newString == trimmed); // if they are identical, you can be sure that original string is an integer
}
This function will return true if a string you put in is really an integer. It can be modified if you don't want trimming. Using leading zeroes will fail, but, once again, you can get rid of them in this function if you want. This way, you don't need to mess around with NaN
or regex, you can easily check validity of your stringified integer.
精彩评论