在JavaScript中验证十进制数字最干净、最有效的方法是什么?

奖励积分:

清晰解决方案应干净简单。跨平台。

测试用例:

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

当前回答

@Zoltan Lengyel在@CMS 12月的回答(2009年2月,5:36)中对“其他地区”的评论(4月26日,2:14):

我建议测试typeof(n)==“string”:

    function isNumber(n) {
        if (typeof (n) === 'string') {
            n = n.replace(/,/, ".");
        }
        return !isNaN(parseFloat(n)) && isFinite(n);
    }

这扩展了Zoltans的建议,使其不仅能够测试“本地化数字”,如isNumber('12,50'),还可以测试“纯”数字,如isNumber(2011)。

其他回答

这里有一个非常简单的(在Chrome、Firefox和IE中测试):

function isNumeric(x) {
  return parseFloat(x) == x;
}

来自问题的测试用例:

console.log('trues');
console.log(isNumeric('-1'));
console.log(isNumeric('-1.5'));
console.log(isNumeric('0'));
console.log(isNumeric('0.42'));
console.log(isNumeric('.42'));

console.log('falses');
console.log(isNumeric('99,999'));
console.log(isNumeric('0x89f'));
console.log(isNumeric('#abcdef'));
console.log(isNumeric('1.2.3'));
console.log(isNumeric(''));
console.log(isNumeric('blah'));

更多测试用例:

console.log('trues');
console.log(isNumeric(0));
console.log(isNumeric(-1));
console.log(isNumeric(-500));
console.log(isNumeric(15000));
console.log(isNumeric(0.35));
console.log(isNumeric(-10.35));
console.log(isNumeric(2.534e25));
console.log(isNumeric('2.534e25'));
console.log(isNumeric('52334'));
console.log(isNumeric('-234'));
console.log(isNumeric(Infinity));
console.log(isNumeric(-Infinity));
console.log(isNumeric('Infinity'));
console.log(isNumeric('-Infinity'));

console.log('falses');
console.log(isNumeric(NaN));
console.log(isNumeric({}));
console.log(isNumeric([]));
console.log(isNumeric(''));
console.log(isNumeric('one'));
console.log(isNumeric(true));
console.log(isNumeric(false));
console.log(isNumeric());
console.log(isNumeric(undefined));
console.log(isNumeric(null));
console.log(isNumeric('-234aa'));

注意,它认为无穷大是一个数。

被接受的答案没有通过你的7号考试,我想这是因为你改变了主意。所以这是对公认答案的回应,我对此有异议。

在一些项目中,我需要验证一些数据,并尽可能确定它是可以用于数学运算的javascript数值。

jQuery和其他一些javascript库已经包含了这样一个函数,通常称为isNumeric。在stackoverflow上也有一篇文章被广泛接受作为答案,这与前面提到的库所使用的一般例程相同。

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

首先,如果参数是长度为1的数组,并且单个元素的类型被上述逻辑视为数字,则上述代码将返回true。在我看来,如果它是一个数组,那么它就不是数字。

为了缓解这个问题,我从逻辑中添加了一个对折扣数组的检查

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n);
}

当然,您也可以使用Array.isArray、jquery$.isArray或原型Object.isArra,而不是Object.protype.toString.call(n)!=='[object数组]'

我的第二个问题是,负十六进制整数文本字符串(“-0xA”->-10)没有被计算为数字。但是,正十六进制整数文本字符串(“0xA”->10)被视为数字。我需要两者都是有效的数字。

然后我修改了逻辑以将其考虑在内。

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

如果您担心每次调用函数时都会创建正则表达式,那么可以在闭包中重写它,如下所示

var isNumber = (function () {
  var rx = /^-/;
   
  return function (n) {
      return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(rx, ''));
  };
}());

然后,我采用了CMS+30测试用例,并在jsfiddle上克隆了测试,并添加了额外的测试用例和上述解决方案。

它可能不会取代广泛接受/使用的答案,但如果这是您期望的isNumeric函数的结果,那么希望这会有所帮助。

编辑:正如Bergi所指出的,还有其他可能的对象可以被视为数字对象,最好将其列入白名单,而不是列入黑名单。考虑到这一点,我将增加标准。

我希望我的isNumeric函数只考虑数字或字符串

考虑到这一点,最好使用

function isNumber(n) {
  return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

测试解决方案

var testHelper=函数(){var testSuite=函数(){test(“Integer Literals”,函数(){ok(isNumber(“-10”),“负整数字符串”);ok(isNumber(“0”),“零字符串”);ok(isNumber(“5”),“正整数字符串”);ok(isNumber(-16),“负整数”);ok(isNumber(0),“零整数”);ok(isNumber(32),“正整数”);ok(isNumber(“040”),“八进制整数字符串”);ok(isNumber(0144),“八进制整数文字”);ok(isNumber(“-040”),“负八进制整数字符串”);ok(isNumber(-0144),“负八进制整数文字”);ok(isNumber(“0xFF”),“十六进制整数字符串”);ok(isNumber(0xFFF),“十六进制整数文字”);ok(isNumber(“-0xFF”),“负十六进制整数字符串”);ok(isNumber(-0xFFF),“负十六进制整数文字”);});测试(“Foating Point Literals”,函数(){ok(isNumber(“-1.6”),“负浮点字符串”);ok(isNumber(“4.536”),“正浮点字符串”);ok(isNumber(-2.6),“负浮点数”);ok(isNumber(3.1415),“正浮点数”);ok(isNumber(8e5),“指数表示法”);ok(isNumber(“123e-2”),“指数符号字符串”);});测试(“非数值”,函数(){equals(isNumber(“”),false,“空字符串”);equals(isNumber(“”),false,“空白字符串”);equals(isNumber(“\t\t”),false,“制表符字符串”);等于(isNumber(“abcdefghijklm123467890”),false,“字母数字字符串”);等于(isNumber(“xabcdefx”),false,“非数字字符串”);equals(isNumber(true),false,“Boolean true literal”);equals(isNumber(false),false,“Boolean false literal”);等于(isNumber(“bcfed5.2”),false,“前面有非数字字符的数字”);等于(isNumber(“7.2acdgs”),false,“带尾随非数字字符的数字”);equals(isNumber(undefined),false,“未定义值”);equals(isNumber(null),false,“null值”);等于(isNumber(NaN),false,“NaN值”);equals(isNumber(无限),false,“无限基元”);等于(isNumber(Number.POSITIVE_INFINITY),false,“正无穷大”);等于(isNumber(Number.NEGATIVE_INFINITY),false,“负无穷大”);等于(isNumber(新日期(2009,1,1)),false,“日期对象”);equals(isNumber(new Object()),false,“空对象”);equals(isNumber(function(){}),false,“函数的实例”);equals(isNumber([]),false,“空数组”);equals(isNumber([“-10”]),false,“数组负整数字符串”);equals(isNumber([“0”]),false,“Array Zero string”);equals(isNumber([“5”]),false,“数组正整数字符串”);等于(isNumber([-16]),false,“数组负整数”);equals(isNumber([0]),false,“Array Zero integer number”);equals(isNumber([32]),false,“数组正整数”);equals(isNumber([“040”]),false,“数组八进制整数字符串”);equals(isNumber([0144]),false,“数组八进制整数文字”);equals(isNumber([“-040”]),false,“数组负八进制整数字符串”);equals(isNumber([-0144]),false,“数组负八进制整数文字”);equals(isNumber([“0xFF”]),false,“数组十六进制整数字符串”);equals(isNumber([0xFFF]),false,“数组十六进制整数文字”);equals(isNumber([“-0xFF”]),false,“数组负十六进制整数字符串”);等于(isNumber([-0xFFF]),false,“数组负十六进制整数文字”);equals(isNumber([1,2]),false,“具有1个以上正整数的数组”);equals(isNumber([-1,-2]),false,“具有1个以上负整数的数组”);});}var函数ToTest=[函数(n){回来isNaN(parseFloat(n))&&isFinite(n);},函数(n){回来isNaN(n)&&!isNaN(parseFloat(n));},函数(n){回来isNaN((n));},函数(n){回来isNaN(parseFloat(n));},函数(n){返回类型(n)!=“布尔”&&!isNaN(n);},函数(n){return parseFloat(n)==数字(n);},函数(n){return parseInt(n)==数字(n);},函数(n){回来isNaN(数字(字符串(n)));},函数(n){回来isNaN(+(“”+n));},函数(n){返回(+n)==n;},函数(n){返回n&&/^-?\d+(\.\d+)?$/。测试(n+“”);},函数(n){return isFinite(数字(字符串(n)));},函数(n){return isFinite(字符串(n));},函数(n){回来isNaN(n)&&!isNaN(parseFloat(n))&&isFinite(n);},函数(n){返回parseFloat(n)==n;},函数(n){return(n-0)==n&&n长度>0;},函数(n){返回类型n==“number”&&isFinite(n);},函数(n){回来Array.isArray(n)&&!isNaN(parseFloat(n))&&isFinite(n.toString().replace(/^-/,“”));}];//检查函数ToTest数组,提取每个函数的返回语句//并填充toTest select元素。var fillToTestSelect=函数(){对于(var i=0;i<functionsToTest.length;i++){var f=函数ToTest[i].toString();var option=/[\s\s]*return([\s\s]*);/。执行(f)[1];$(“#toTest”).append('<option value=“'+i+'”>'+(i+1)+'.'+option+'</option>');}}var performTest=函数(函数编号){reset();//重置上一测试$(“#tests”).html(“”)//清洁测试结果isNumber=函数ToTest[函数编号];//用要测试的函数重写isNumber全局函数testSuite();//运行测试//获取测试结果var totalFail=0;v

这里有一个稍微改进的版本(可能是最快的版本),我用它代替了jQuery的变体,我真的不知道他们为什么不使用这个:

function isNumeric(val) {
    return !isNaN(+val) && isFinite(val);
}

jQuery版本的缺点是,如果您传递一个带前导数字和尾随字母(如“123abc”)的字符串,parseFloat|parseInt将提取数字分数并返回123,但第二个保护isFinite无论如何都会失败。使用一元+运算符,它将在第一个守卫中死亡,因为+为此类混合体抛出NaN:)虽然有点表现,但我认为语义上有了坚实的收获。

通过利用语言的动态类型检查,一个简单而干净的解决方案:

function IsNumeric (string) {
   if(string === ' '.repeat(string.length)){
     return false
   }
   return string - 0 === string * 1
}

如果你不在乎空格,你可以删除“如果”

参见下面的测试用例

函数IsNumeric(字符串){if(string==''.repeat(string.length)){return false}返回字符串-0===string*1}console.log('-1'+'→ ' + IsNumeric('-1'))console.log('-1.5'+'→ ' + IsNumeric('-1.5'))console.log(“0”+“→ ' + IsNumeric(“0”)console.log(“0.42”+“→ ' + IsNumeric(“0.42”)console.log('.42'+'→ ' + IsNumeric('.42'))console.log('99999'+'→ ' + IsNumeric(“99999”)console.log('0x89f'+'→ ' + IsNumeric('0x89f'))console.log('#abcdef'+'→ ' + IsNumeric(“#abcdef”)console.log('1.2.3'+'→ ' + IsNumeric('1.2.3'))console.log(“+”→ ' + IsNumeric(“”))console.log('33'+'→ ' + IsNumeric(“33”)

对于空字符串,没有一个答案返回false,对此进行了修复。。。

function is_numeric(n)
{
 return (n != '' && !isNaN(parseFloat(n)) && isFinite(n));
}