在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

当前回答

啊!不要听正则表达式的答案。RegEx很讨厌这个,我说的不仅仅是性能。用正则表达式很容易发现细微的、不可能发现的错误。

如果您不能使用isNaN(),这应该会更好:

function IsNumeric(input)
{
    return (input - 0) == input && (''+input).trim().length > 0;
}

以下是它的工作原理:

(input-0)表达式强制JavaScript对输入值执行类型强制;它必须首先被解释为减法运算的数字。如果转换为数字失败,表达式将生成NaN。然后将此数字结果与传入的原始值进行比较。由于左侧现在是数字,因此再次使用类型强制。既然来自双方的输入被强制为来自相同原始值的相同类型,那么您会认为它们应该总是相同的(总是正确的)。然而,有一条特殊规则规定NaN永远不等于NaN,因此不能转换为数字的值(只有不能转换为数值的值)将导致错误。

长度检查用于涉及空字符串的特殊情况。还要注意,这取决于0x89f测试,但这是因为在许多环境中,这是定义数字文字的好方法。如果您想捕捉特定场景,可以添加额外的检查。更好的是,如果这是您不使用isNaN()的原因,那么只需将您自己的函数包装在isNaN)周围,这也可以进行额外的检查。

总之,如果您想知道某个值是否可以转换为数字,请尝试将其转换为数字。


我回去研究了为什么空白字符串没有预期的输出,我想我现在明白了:空字符串被强制为0而不是NaN。只需在长度检查之前修剪字符串即可处理这种情况。

针对新代码运行单元测试,它只会在无穷大和布尔文本上失败,唯一可能出现问题的是,如果你正在生成代码(真的,谁会键入文本并检查它是否为数字?你应该知道),那将是一些奇怪的代码。

但是,再次强调,使用此选项的唯一原因是,如果出于某种原因,您必须避免使用isNaN()。

其他回答

我认为parseFloat函数可以完成这里的所有工作。下面的函数通过了此页面上的所有测试,包括isNumeric(Infinity)==true:

function isNumeric(n) {

    return parseFloat(n) == n;
}

最好的方法如下:

function isThisActuallyANumber(data){
    return ( typeof data === "number" && !isNaN(data) );
}

@Joel的答案很接近,但在以下情况下会失败:

// Whitespace strings:
IsNumeric(' ')    == true;
IsNumeric('\t\t') == true;
IsNumeric('\n\r') == true;

// Number literals:
IsNumeric(-1)  == false;
IsNumeric(0)   == false;
IsNumeric(1.1) == false;
IsNumeric(8e5) == false;

前段时间,我必须实现一个IsNumeric函数,以确定一个变量是否包含一个数值,无论其类型如何,它可能是一个包含数值的字符串(我还必须考虑指数表示法等),一个Number对象,实际上任何东西都可以传递给该函数,我无法做出任何类型假设,注意类型强制(例如,+true==1;但true不应被视为“数字”)。

我认为值得分享这组针对众多功能实现所做的+30个单元测试,并分享通过我所有测试的测试:

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

P.S.isNaN和isFinite由于强制转换为数字而具有令人困惑的行为。在ES6中,Number.isNaN和Number.isFinite可以解决这些问题。使用它们时请记住这一点。


更新:jQuery现在是如何做到的(2.2稳定):

isNumeric: function(obj) {
    var realStringObj = obj && obj.toString();
    return !jQuery.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
}

更新:角度4.3:

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}

@CMS的回答:您的代码段在我的机器上使用nodejs处理空白情况时失败。所以我把它和@joel对以下问题的回答:

is_float = function(v) {
    return !isNaN(v) && isFinite(v) &&
        (typeof(v) == 'number' || v.replace(/^\s+|\s+$/g, '').length > 0);
}

我用那些浮动的案例对其进行了统一测试:

var t = [
        0,
        1.2123,
        '0',
        '2123.4',
        -1,
        '-1',
        -123.423,
        '-123.432',
        07,
        0xad,
        '07',
        '0xad'
    ];

以及那些没有浮点数的情况(包括空白空格和对象/数组):

    var t = [
        'hallo',
        [],
        {},
        'jklsd0',
        '',
        "\t",
        "\n",
        ' '
    ];

这里的一切都按预期进行。也许这有帮助。

这里可以找到完整的源代码。

@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)。