如何检查一个字符串是否是有效的数字?

1911

我希望有与旧的VB6 IsNumeric()函数在同一概念空间中的东西?


5
请参考我之前提出的相关问题此链接 - Michael Haren
55
如果您查看这个问题,请尽量跳过所有正则表达式的答案。那不是解决问题的正确方式。 - Joel Coehoorn
18
除非有人想要做这件事:检查给定字符串是否具有有效数字流的格式。那么为什么这样做是错的呢? - SasQ
41
选定的答案是不正确的!!!请查看其评论,但基本上它在例如isNaN("")isNaN(" ")isNaN(false)等情况下失败了。它返回false,这意味着它们是数字。 - Andrew
11
所选答案是不正确的,正则表达式也不能解决这个问题。那么正确的方法是什么? - vir us
显示剩余3条评论
53个回答

17

有些人可能也会从基于正则表达式的答案中受益。这里是:

一行代码判断整数:

const isInteger = num => /^-?[0-9]+$/.test(num+'');

一行代码判断是否为数字: 接受整数和小数

const isNumeric = num => /^-?[0-9]+(?:\.[0-9]+)?$/.test(num+'');

这段代码存在一个问题,即将空格视为无效字符。如果这不是你想要的结果,那么最好使用 const isInteger = num => /^\s*-?[0-9]+\s*$/.test(num+''); 或者 const isNumeric = num => /^\s*-?[0-9]+(?:\.[0-9]+)\s*?$/.test(num+''); - yoel halb
2
@yoelhalb 空格是一个数字无效的字符。您可以在传递字符串之前对其进行修剪。 - chickens
空字符串不是数字。但我猜这是真的 ;) - windmaomao
这也没有考虑到其他数字格式的方式,例如十六进制数和科学计数法。 - R. Agnese

16

我已经测试过,Michael的解决方案是最好的。请投票支持他在上面的答案(在本页中搜索“如果你确实想要确保一个字符串”即可找到它)。总的来说,他的回答就是这样:

function isNumeric(num){
  num = "" + num; //coerce num to be a string
  return !isNaN(num) && !isNaN(parseFloat(num));
}

这个方法适用于我在这里记录的每一个测试用例: https://jsfiddle.net/wggehvp9/5/

其他很多解决方案都无法处理以下边缘情况: ' '(空格),null,""(空字符串),true和[](空数组)。 理论上,你可以使用它们,并进行适当的错误处理,例如:

return !isNaN(num);
或者
return (+num === +num);

对于 /\s/, null, "", true, false, [](以及其他一些情况),需要进行特殊处理。


1
这仍然会返回带有前导/尾随空格的true。将类似以下内容添加到return语句中可以解决这个问题:&& !/^\s+|\s+$/g.test(str) - Ultroman the Tacoman
2
所以 ' 123' 应该是 false,不是一个数字,而 '1234' 应该是一个数字?我喜欢它的方式,这样 " 123" 就是一个数字,但如果前导或尾随空格应该改变值,则可能取决于开发人员的判断。 - JohnP2

12
你可以将 Number 的结果作为其构造函数的参数。
如果传入的参数(一个字符串)无法转换为数字,则会返回NaN,因此您可以确定提供的字符串是否为有效数字。
注意:当将空字符串或 '\t\t''\n\t' 作为参数传递给 Number 时,它将返回 0;传递 true 将返回 1,false 返回 0。
    Number('34.00') // 34
    Number('-34') // -34
    Number('123e5') // 12300000
    Number('123e-5') // 0.00123
    Number('999999999999') // 999999999999
    Number('9999999999999999') // 10000000000000000 (integer accuracy up to 15 digit)
    Number('0xFF') // 255
    Number('Infinity') // Infinity  

    Number('34px') // NaN
    Number('xyz') // NaN
    Number('true') // NaN
    Number('false') // NaN

    // cavets
    Number('    ') // 0
    Number('\t\t') // 0
    Number('\n\t') // 0

Number 构造函数与 +x 完全相同。 - GregRos
顺便提一下,记住ES6的Number()也可以处理浮点数,就像Number.parseFloat()而不是Number.parseInt() - zurfyx

10

也许有一两个人遇到了这个问题,需要比通常更严格的检查(就像我一样)。如果是这种情况,这可能会有用:

if(str === String(Number(str))) {
  // it's a "perfectly formatted" number
}

注意!这将拒绝像.140.00008000.1这样的字符串。它非常挑剔 - 字符串必须与数字的“最小完美形式”匹配,才能通过此测试。

它使用StringNumber构造函数将字符串转换为数字,然后再次转换回来,从而检查JavaScript引擎的“完美最小形式”(它使用初始Number构造函数进行转换)是否与原始字符串匹配。


2
感谢@JoeRocc。 我也需要这个,但仅适用于整数,因此我添加了: (str === String(Math.round(Number(str)))) - keithpjolley
请注意,"Infinity""-Infinity""NaN" 会通过此测试。不过,可以使用额外的 Number.isFinite 测试来解决这个问题。 - GregRos
1
这与 str === ("" + +str) 完全相同。它基本上检查字符串是否是 JS 数字的字符串化结果。了解这一点,我们也可以看到一个问题:测试对于 0.000001 通过,但对于 0.0000001 失败,此时应该使用 1e-7 通过。对于非常大的数字也是如此。 - GregRos
这个答案是不正确的。1e10 是“完全有效和格式化”的,但它仍然无法通过此算法。 - Ben Aston

7

我喜欢这个简单易懂的设计。

Number.isNaN(Number(value))

上述内容是常规的Javascript,但我与typescript类型守卫结合使用,以进行智能类型检查。这对Typescript编译器为您提供正确的智能感知和无类型错误非常有用。

Typescript类型守卫

警告:请参见Jeremy下面的评论。 这在某些值方面存在一些问题,我现在没有时间来修复它,但使用typescript类型守卫的想法很有用,因此我不会删除此部分。

isNotNumber(value: string | number): value is string {
    return Number.isNaN(Number(this.smartImageWidth));
}
isNumber(value: string | number): value is number {
    return Number.isNaN(Number(this.smartImageWidth)) === false;
}

假设您有一个属性width,它可以是number | string。您可能想基于它是否为字符串执行逻辑操作。
var width: number|string;
width = "100vw";

if (isNotNumber(width)) 
{
    // the compiler knows that width here must be a string
    if (width.endsWith('vw')) 
    {
        // we have a 'width' such as 100vw
    } 
}
else 
{
    // the compiler is smart and knows width here must be number
    var doubleWidth = width * 2;    
}

类型守卫足够聪明,可以将width的类型限制在if语句中,仅为string。这允许编译器允许width.endsWith(...),如果类型是string | number,则不会允许。

您可以随意命名类型守卫,例如isNotNumberisNumberisStringisNotString,但我认为isString有点含糊不清并且更难读懂。


2
在普通JS中运行相对良好,但无法处理像1..11,1-32.1.12等情况,更重要的是无法处理undefinedNaN。不确定你的TS是否可以弥补这一点,但看起来如果传递了undefinedNaN,它将尝试执行undefined * 2,这不会崩溃,但会返回NaN - Jeremy
请注意,此方法允许数字中出现 eE(例如 2E34),因为它被认为是有效的数字(“科学计数法”),但这不一定是您想要的... - yoel halb

7

2019年:实用严格的数字有效性检查

通常,“有效数字”指的是JavaScript数字,不包括NaN和Infinity,即“有限数字”。

要检查值(例如来自外部来源的值)的数字有效性,您可以在ESlint Airbnb风格中定义:

/**
 * Returns true if 'candidate' is a finite number or a string referring (not just 'including') a finite number
 * To keep in mind:
 *   Number(true) = 1
 *   Number('') = 0
 *   Number("   10  ") = 10
 *   !isNaN(true) = true
 *   parseFloat('10 a') = 10
 *
 * @param {?} candidate
 * @return {boolean}
 */
function isReferringFiniteNumber(candidate) {
  if (typeof (candidate) === 'number') return Number.isFinite(candidate);
  if (typeof (candidate) === 'string') {
    return (candidate.trim() !== '') && Number.isFinite(Number(candidate));
  }
  return false;
}

并按照以下方式使用:

if (isReferringFiniteNumber(theirValue)) {
  myCheckedValue = Number(theirValue);
} else {
  console.warn('The provided value doesn\'t refer to a finite number');
}

7
为什么jQuery的实现不够好?
function isNumeric(a) {
    var b = a && a.toString();
    return !$.isArray(a) && b - parseFloat(b) + 1 >= 0;
};

迈克尔建议这样做(尽管我在这里偷了“user1691651 - John”的修改版本):

function isNumeric(num){
    num = "" + num; //coerce num to be a string
    return !isNaN(num) && !isNaN(parseFloat(num));
}

以下是一种性能可能不佳但结果稳定的解决方案。它是由jQuery 1.12.4实现和Michael的答案构成的装置,额外增加了对前导/尾随空格的检查(因为Michael的版本对带有前导/尾随空格的数字返回true):
function isNumeric(a) {
    var str = a + "";
    var b = a && a.toString();
    return !$.isArray(a) && b - parseFloat(b) + 1 >= 0 &&
           !/^\s+|\s+$/g.test(str) &&
           !isNaN(str) && !isNaN(parseFloat(str));
};

后一个版本有两个新变量,但其中一个可以通过以下方式解决:
function isNumeric(a) {
    if ($.isArray(a)) return false;
    var b = a && a.toString();
    a = a + "";
    return b - parseFloat(b) + 1 >= 0 &&
            !/^\s+|\s+$/g.test(a) &&
            !isNaN(a) && !isNaN(parseFloat(a));
};

我还没有对这些进行过太多测试,除了手动测试我目前遇到的一些标准问题的少数用例。这是一个“站在巨人的肩膀上”的情况。


6

对于TypeScript而言,这段代码是无效的:

declare function isNaN(number: number): boolean;

你可以使用以下代码来代替:

/^\d+$/.test(key)


/^\d+$/.test("-1") // false 要在TS中使用isNaN处理非数字,您只需要将值转换为any,或者使用这里的其他更全面的解决方案之一,它们利用了NumberparseFloat等。 - John Montgomery

6

使用parseInt()函数将字符串转换为整数,但要注意这个函数有些不同,例如对于parseInt("100px")的情况,它会返回100。


以及 parseInt(09) 的结果为11。 - djechlin
12
因为你需要使用 paraseInt(09, 10) - Gavin
2
从ECMAScript 5开始(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#Octal_interpretations_with_no_radix),由于支持广泛(IE≥9),你不再需要使用`,10`参数。 现在parseInt('09')等于9。 - Rory O'Kane

5

这种方法对我有效。

function isNumeric(num){
    let value1 = num.toString();
    let value2 = parseFloat(num).toString();
    return (value1 === value2);
}

console.log(
    isNumeric(123),     //true
    isNumeric(-123),    //true
    isNumeric('123'),   //true
    isNumeric('-123'),  //true
    isNumeric(12.2),    //true
    isNumeric(-12.2),   //true
    isNumeric('12.2'),  //true
    isNumeric('-12.2'), //true
    isNumeric('a123'),  //false
    isNumeric('123a'),  //false
    isNumeric(' 123'),  //false
    isNumeric('123 '),  //false
    isNumeric('a12.2'), //false
    isNumeric('12.2a'), //false
    isNumeric(' 12.2'), //false
    isNumeric('12.2 '), //false
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接