验证字符串是否为正整数

IT技术 javascript
2021-02-01 12:18:21

我想要最简单的故障安全测试来检查 JavaScript 中的字符串是否为正整数。

isNaN(str)为各种非整数值返回 true,并parseInt(str)为浮点字符串返回整数,如“2.5”。而且我也不想使用一些 jQuery 插件。

6个回答

给你两个答案:

  • 基于解析

  • 正则表达式

请注意,在这两种情况下,我都将“正整数”解释为 include 0,即使0不是正数。如果您想禁止0.

基于解析

如果您希望它是一个合理范围内的标准化十进制整数字符串,您可以这样做:

function isInDesiredForm(str) {
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}

或者,如果您想允许空格和前导零:

function isInDesiredForm(str) {
    str = str.trim();
    if (!str) {
        return false;
    }
    str = str.replace(/^0+/, "") || "0";
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}

实时测试台(不处理前导零或空格):

现场测试平台(处理的前导零和空格):

如果您想禁止0,只需更改>= 0> 0. (或者,在允许前导零的版本中,删除|| "0"replace行。)

它是如何工作的:

  1. 在允许空格和前导零的版本中:
  • str = str.trim(); 删除任何前导和尾随空格。
  • if (!str) 捕获一个空白字符串并返回,做其余的工作没有意义。
  • str = str.replace(/^0+/, "") || "0"; 从字符串中删除所有前导 0——但如果这导致一个空白字符串,则恢复单个 0。
  1. Number(str): 转换str为数字;该数字可能有一个小数部分,或者可能是NaN

  2. Math.floor:截断数字(切掉任何小数部分)。

  3. String(...): 将结果转换回普通的十进制字符串。对于非常大的数字,这将采用科学记数法,这可能会破坏这种方法。(我不太清楚拆分的位置,详细信息在规范中,但是对于整数,我相信您已经超过了 21 位 [到那时,数字变得非常不精确,因为 IEEE-754双精度数字只有大约 15 位精度..)

  4. ... === str: 将其与原始字符串进行比较。

  5. n >= 0: 检查是否为阳性。

请注意,这对于 input "+1"、任何在该String(...)阶段不会变回相同科学记数法的科学记数法输入以及 JavaScript 使用的数字类型(IEEE-754 双精度二进制浮点数)的任何值都失败了无法准确表示哪个解析比给定的值更接近不同的值(其中包括超过 9,007,199,254,740,992 的许多整数;例如,1234567890123456789将失败)。前者很容易解决,后两者不太好。

正则表达式

另一种方法是通过正则表达式测试字符串的字符,如果您的目标是只允许(比如说)一个可选的,+后跟一个0或一个普通十进制格式的字符串:

function isInDesiredForm(str) {
    return /^\+?(0|[1-9]\d*)$/.test(str);
}

现场测试台:

它是如何工作的:

  1. ^: 匹配字符串的开头

  2. \+?: 允许一个,可选的+(如果你不想删除这个)

  3. (?:...|...):允许以下两个选项之一(不创建捕获组):

  4. (0|...): 允许0自己...

  5. (...|[1-9]\d*): ... 或以其他数字开头0并后跟任意数量的十进制数字的数字。

  6. $: 匹配字符串的结尾。

如果你想禁止0(因为它不是肯定的),正则表达式就会变成 just /^\+?[1-9]\d*$/(例如,我们可能会失去我们需要允许的交替0)。

如果您想允许前导零 (0123, 00524),则只需将交替替换(?:0|[1-9]\d*)\d+

function isInDesiredForm(str) {
    return /^\+?\d+$/.test(str);
}

如果您想允许空格,请\s*在 之后^\s*之前添加$

将其转换为数字时的注意事项:在现代引擎上使用+strNumber(str)执行它可能没问题,但较旧的引擎可能会以非标准(但以前允许)的方式扩展它们,即前导零表示八进制(基数 8),例如“010”=> 8。一旦您验证了数字,您就可以安全地使用parseInt(str, 10)它来确保它被解析为十进制(基数 10)。parseInt会忽略字符串末尾的垃圾,但我们确保正则表达式中没有垃圾。

@TJCrowder 好的,但我确实需要像 ''2a''这样的字符串以某种方式被拒绝,parseInt返回2.
2021-03-22 12:18:21
@phkavitha:JavaScript 性能问题的答案几乎总是“视情况而定”,因为不同的引擎彼此如此不同。您可以使用jsperf.com测试您的目标引擎/浏览器我不认为此操作可能会成为任何给定应用程序的瓶颈... :-)
2021-03-23 12:18:21
bothNumber(' ')Number('')return 0while 应该返回NaN
2021-04-03 12:18:21
@neurino:/\D/.test('2a')是真的(因为有一个非数字)。所以也许if (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}......就在我的头顶......
2021-04-07 12:18:21
性能方面,哪种方法会更快?或者哪一种是可取的?
2021-04-08 12:18:21

方案一

如果我们将 JavaScript 整数视为最大值4294967295(即Math.pow(2,32)-1),那么以下简短的解决方案将完美适用:

function isPositiveInteger(n) {
    return n >>> 0 === parseFloat(n);
}

描述:

  1. 零填充右移运算符做了三件重要的事情:
    • 截断小数部分
      • 123.45 >>> 0 === 123
    • 负数的移位
      • -1 >>> 0 === 4294967295
    • 范围内的“作品” MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloat正确解析字符串数字(NaN非数字字符串的设置

测试:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e7"                  : false
"1e7"                   : true
"1e10"                  : false
"1edf"                  : false
" "                     : false
""                      : false

演示: http : //jsfiddle.net/5UCy4/37/


解决方案2

另一种方法适用于有效至Number.MAX_VALUE,即至 about 的所有数值1.7976931348623157e+308

function isPositiveInteger(n) {
    return 0 === n % (!isNaN(parseFloat(n)) && 0 <= ~~n);
}

描述:

  1. !isNaN(parseFloat(n))用于过滤字符串值,例如"", " ", "string";
  2. 0 <= ~~n过滤负值和大的非整数值,例如"-40.1""129000098131766699"
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n)true如果 value 既是数字又是返回
  4. 0 === n % (...)检查,如果值不浮-在这里(...)(参见图3)被评价为0在以下情况下false,并且如1在以下情况下true

测试:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e10"                 : false
"1e10"                  : true
"1edf"                  : false
" "                     : false
""                      : false

演示: http : //jsfiddle.net/5UCy4/14/


之前的版本:

function isPositiveInteger(n) {
    return n == "0" || ((n | 0) > 0 && n % 1 == 0);
}

演示: http : //jsfiddle.net/5UCy4/2/

我在 JavaScript 世界中花的时间不多,所以对零填充右移运算符解决方案 +1。这很棒而且很简单。我的一个挑剔是,它仍然为带小数的整数返回 true,而无需进行额外检查。所以如果我想用它来验证用户输入,1.并且1.00000会返回 true。
2021-03-22 12:18:21
这个甚至可以处理填充的零(很好!)。您可以将其添加到您的测试中。
2021-03-23 12:18:21
很好的答案。就个人而言,为了可读性,我更喜欢冗长一点(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
2021-04-04 12:18:21
尝试使用空字符串或大数字,例如 1290000981231123.1 - jsfiddle.net/5UCy4/1
2021-04-11 12:18:21
@gdoron 与 相同~~val,截断小数部分。由于执行一次按位运算而不是两次,因此速度要快一些。
2021-04-12 12:18:21

看起来正则表达式是要走的路:

var isInt = /^\+?\d+$/.test('the string');
这是一个非常不精确的解决方案。
2021-03-15 12:18:21
关闭,除非允许“1.0”或“.1e1”。
2021-03-24 12:18:21
它不会检查范围最多为 2^31-1,也不允许阿拉伯数字。这是一个黑客,不是一个好的解决方案。最好的解决方案在这个问题上获得最多的赞成票。为什么不使用那个?在各方面都更好。
2021-03-27 12:18:21
那么 1290000192379182379123782900192981231 是一个整数,但它不能完全用 JavaScript 原生数字表示,所以使用正则表达式仍然需要进行数字转换并验证它是否有效。
2021-04-02 12:18:21
@usr:我想它允许0在您通常不期望的地方领先,但在大多数情况下,似乎很好。
2021-04-07 12:18:21

适用于 node 和超过 90% 的所有浏览器(IE 和 Opera Mini 除外)的现代解决方案是使用Number.isInteger后跟一个简单的肯定检查。

Number.isInteger(x) && x > 0

在 ECMAScript 2015完成

function isPositiveInteger(x) {
    return Number.isInteger(x) && x > 0
}

Polyfil 是:

Number.isInteger = Number.isInteger || function(value) {
  return typeof value === 'number' && 
    isFinite(value) && 
    Math.floor(value) === value;
};

如果您需要支持可能是字符串数字形式的输入,那么您可以使用这个函数,我编写了一个大型测试套件,因为所有现有答案 (2/1/2018) 在某种形式的输入上都失败了。

function isPositiveInteger(v) {
  var i;
  return v && (i = parseInt(v)) && i > 0 && (i === v || ''+i === v);
}
该问题专门询问如何测试字符串是否为正整数。
2021-04-04 12:18:21

ES6:

Number.isInteger(Number(theNumberString)) && Number(theNumberString) > 0
你是对的!我更新了,我发现自己脸红了。谢谢你指出。
2021-03-14 12:18:21
isInteger返回一个布尔值,然后与0.
2021-04-02 12:18:21