验证字符串是否为正整数


200

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

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


7
你允许“ +2”吗?“ 0.1e1”怎么样?“ 1.0000”怎么样?
Phrogz

isNaN()功能的行为方式是因为该概念Not a Number在IEEE 794浮点规范中具有非常特定的含义。它不打算为简单的口语问题提供答案,“这个值不是数字吗?”
尖尖的

3
这个问题非常模糊。您无法验证“字符串是整数”,因为没有这样的东西-任何对象都不能同时是字符串和数字。您可能的意思是“如何测试字符串是否是整数的有效表示形式”,但要回答此问题,我们需要知道您在说哪种语言或“文化”。例如,٢‎٣٤MCMXIX都是有效的整数表示形式,但我不认为您正在寻找能够解析这些整数的代码。您是否可以指定要支持的数字格式,因为人们对此感到困惑。
乔治,2012年

5
我认为“含糊不清”本身有点极端。但无论如何...上下文是在英语国家/地区使用的购物车上的数量输入字段的验证,因此仅是西方数字。“正”是指大于零。我会接受以下内容:“ +2”是,“ 0.1e1”否,“ 1.000”,为什么不呢?但是,如果您提供的答案可以调整为包括/排除这些各种特殊情况,那么我保证会给您额外的帮助(我敢肯定其他人也会这样做)。
米克·伯恩

Answers:


296

为您提供两个答案:

  • 基于解析

  • 正则表达式

请注意,在两种情况下,我都将“正整数”解释为包括0,即使0它不是正数。如果您不愿意,我会提供注释0

基于解析

如果希望它是在合理值范围内的归一化十进制整数字符串,则可以执行以下操作:

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

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

function isNormalInteger(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。
  2. Number(str):转换str为数字;该数字可以是小数部分,也可以是NaN

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

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

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

  6. n >= 0:检查结果是否正确。

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

正则表达式

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

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

现场测试台:

工作原理:

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

  2. \+?:允许一个可选的+(如果您不想删除此选项)

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

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

    2. (...|[1-9]\d*):...或以0非十进制数字开头的数字,然后是任意十进制数字。

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

如果您要禁止0(因为它不是正数),则正则表达式将变为公正/^\+?[1-9]\d*$/(例如,我们可能会丢失我们需要允许的替代0)。

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

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

如果你想允许空格,加\s*刚过^\s*之前$

在将其转换为数字时请注意:在现代引擎上,使用+strNumber(str)执行它可能会很好,但是较旧的引擎可能会以非标准(但以前允许)的方式扩展它们,即前导零表示八进制(以8为底),例如“ 010” =>8。验证数字后,可以放心使用parseInt(str, 10)以确保将其解析为十进制(以10为底)。parseInt会在字符串的末尾忽略垃圾,但是我们确保正则表达式没有任何垃圾。


两者Number(' ')Number('')返回,0而应返回NaN
neurino

@TJCrowder确定,但我确实需要像“” 2A“”字符串以某种方式拒绝,parseInt退货2
neurino

@neurino:/\D/.test('2a')是正确的(因为有一个非数字)。所以也许if (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}……就在我的头顶上……
TJ Crowder

性能明智,哪种方法会更快?还是建议哪一个?
phkavitha

@phkavitha:JavaScript性能问题的答案几乎总是“取决于”,因为不同的引擎彼此之间是如此不同。您可以使用jsperf.com测试目标引擎/浏览器。我不认为此操作可能会成为任何给定应用程序的瓶颈... :-)
TJ Crowder 2013年

76

解决方案1

如果我们认为一个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,直到大约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值是否为数值正数
  4. 0 === n % (...)检查value是否为非浮点型-在此处(...)(请参阅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/


尝试输入空字符串或较大的数字,例如1290000981231123.1-jsfiddle.net/5UCy4/1
Niko

@gdoron与一样~~val,切除小数部分。因为执行一次按位操作而不是两次,所以速度更快。
VisioN 2012年

好答案。就个人而言,我希望可读性更高一些(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Ramy Nasr,

true, false, 0xFF,而其他值则使其isPositiveInteger无法被检测到。
Xeoncross '18年

1
这个甚至可以处理填充的零(好!)。您可以将其添加到测试中。
Rashack

21

看起来正则表达式是解决方法:

var isInt = /^\+?\d+$/.test('the string');

关闭,除非允许使用“ 1.0”或“ .1e1”。
Phrogz

12900001923791823791237829001900192981231是一个整数,但不能完全用JavaScript本机数字表示,因此使用正则表达式仍需要进行数字转换并验证其是否有效。
尖尖的

这是一个非常不精确的解决方案。
usr 2012年

@usr:我想它可以引导0您通常不会想到的地方,但是在大多数情况下,这似乎很好。
TJ Crowder

它不会检查范围最大为2 ^ 31-1,并且不允许使用阿拉伯数字。这是一个hack,不是一个好的解决方案。最好的解决方案在这个问题上的投票最多。为什么不使用那个?各个方面都更好。
usr 2012年

17

在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;
};

如果您需要支持字符串数字形式的输入,则可以使用此功能,在所有现有答案(2018年2月1日)以某种形式的输入均失败后,我编写了一个大型测试套件

function isPositiveInteger(v) {
  var i;
  return v && (i = parseInt(v)) && i > 0 && (i === v || ''+i === v);
}

4

这个问题几乎是一个重复的问题:

验证JavaScript中的十进制数字-IsNumeric()

答案是:

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

因此,正整数将是:

function isPositiveInteger(n) {
  var floatN = parseFloat(n);
  return !isNaN(floatN) && isFinite(n) && floatN > 0
      && floatN % 1 == 0;
}

我通读了整个内容,几乎与“验证JavaScript中的数字”问题完全相同,但是我认为一个关于整数的字符串表示形式的问题应归为己有。
米克·伯恩

2
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

如果您输入“ 0001”这样的字符串,将无法正常工作


2

我的函数检查数字是否为+ ve以及是否也可以为十进制值。

       function validateNumeric(numValue){
            var value = parseFloat(numValue);
            if (!numValue.toString().match(/^[-]?\d*\.?\d*$/)) 
                    return false;
            else if (numValue < 0) {
                return false;
            }
            return true;        
        }

2

只是基于以上VisioN的答案,如果您使用的是jQuery验证插件,则可以使用以下代码:

$(document).ready(function() {
    $.validator.addMethod('integer', function(value, element, param) {
        return (value >>> 0 === parseFloat(value) && value > 0);
    }, 'Please enter a non zero integer value!');
}

然后,您可以在常规规则集中使用或以这种方式动态添加它:

$("#positiveIntegerField").rules("add", {required:true, integer:true});

2

简单

function isInteger(num) {
  return (num ^ 0) === num;
}

console.log(isInteger(1));

您还可以扩展Number并通过原型为其分配功能。




0

ES6:

Number.isInteger(Number(theNumberString)) > 0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.