Validate that a string is a positive integer

2020-01-23 15:19发布

I would like the simplest fail-safe test to check that a string in JavaScript is a positive integer.

isNaN(str) returns true for all sorts of non-integer values and parseInt(str) is returning integers for float strings, like "2.5". And I don't want to have to use some jQuery plugin either.

标签: javascript
11条回答
Emotional °昔
2楼-- · 2020-01-23 15:34

Simple

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

console.log(isInteger(1));

You can also extend Number and assign the function to it via prototype.

查看更多
再贱就再见
3楼-- · 2020-01-23 15:41

Looks like a regular expression is the way to go:

var isInt = /^\+?\d+$/.test('the string');
查看更多
ら.Afraid
4楼-- · 2020-01-23 15:42

(~~a == a) where a is the string.

查看更多
Rolldiameter
5楼-- · 2020-01-23 15:43
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

won't work if you give a string like '0001' though

查看更多
甜甜的少女心
6楼-- · 2020-01-23 15:43

Just to build on VisioN's answer above, if you are using the jQuery validation plugin you could use this:

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

Then you could use in your normal rules set or add it dynamically this way:

$("#positiveIntegerField").rules("add", {required:true, integer:true});
查看更多
SAY GOODBYE
7楼-- · 2020-01-23 15:45

Two answers for you:

  • Based on parsing

  • Regular expression

Note that in both cases, I've interpreted "positive integer" to include 0, even though 0 is not positive. I include notes if you want to disallow 0.

Based on Parsing

If you want it to be a normalized decimal integer string over a reasonable range of values, you can do this:

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

or if you want to allow whitespace and leading zeros:

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

Live testbed (without handling leading zeros or whitespace):

function isNormalInteger(str) {
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}
function gid(id) {
    return document.getElementById(id);
}
function test(str, expect) {
    var result = isNormalInteger(str);
    console.log(
        str + ": " +
        (result ? "Yes" : "No") +
        (expect === undefined ? "" : !!expect === !!result ? " <= OK" : " <= ERROR ***")
    );
}
gid("btn").addEventListener(
    "click",
    function() {
        test(gid("text").value);
    },
    false
);
test("1", true);
test("1.23", false);
test("1234567890123", true);
test("1234567890123.1", false);
test("0123", false); // false because we don't handle leading 0s
test(" 123 ", false); // false because we don't handle whitespace
<label>
  String:
  <input id="text" type="text" value="">
<label>
<input id="btn" type="button" value="Check">

Live testbed (with handling for leading zeros and whitespace):

function isNormalInteger(str) {
    str = str.trim();
    if (!str) {
        return false;
    }
    str = str.replace(/^0+/, "") || "0";
    var n = Math.floor(Number(str));
    return String(n) === str && n >= 0;
}
function gid(id) {
    return document.getElementById(id);
}
function test(str, expect) {
    var result = isNormalInteger(str);
    console.log(
        str + ": " +
        (result ? "Yes" : "No") +
        (expect === undefined ? "" : !!expect === !!result ? " <= OK" : " <= ERROR ***")
    );
}
gid("btn").addEventListener(
    "click",
    function() {
        test(gid("text").value);
    },
    false
);
test("1", true);
test("1.23", false);
test("1234567890123", true);
test("1234567890123.1", false);
test("0123", true);
test(" 123 ", true);
<label>
  String:
  <input id="text" type="text" value="">
<label>
<input id="btn" type="button" value="Check">

If you want to disallow 0, just change >= 0 to > 0. (Or, in the version that allows leading zeros, remove the || "0" on the replace line.)

How that works:

  1. In the version allowing whitespace and leading zeros:

    • str = str.trim(); removes any leading and trailing whitepace.
    • if (!str) catches a blank string and returns, no point in doing the rest of the work.
    • str = str.replace(/^0+/, "") || "0"; removes all leading 0s from the string — but if that results in a blank string, restores a single 0.
  2. Number(str): Convert str to a number; the number may well have a fractional portion, or may be NaN.

  3. Math.floor: Truncate the number (chops off any fractional portion).

  4. String(...): Converts the result back into a normal decimal string. For really big numbers, this will go to scientific notation, which may break this approach. (I don't quite know where the split is, the details are in the spec, but for whole numbers I believe it's at the point you've exceeded 21 digits [by which time the number has become very imprecise, as IEEE-754 double-precision numbers only have roughtly 15 digits of precision..)

  5. ... === str: Compares that to the original string.

  6. n >= 0: Check that it's positive.

Note that this fails for the input "+1", any input in scientific notation that doesn't turn back into the same scientific notation at the String(...) stage, and for any value that the kind of number JavaScript uses (IEEE-754 double-precision binary floating point) can't accurately represent which parses as closer to a different value than the given one (which includes many integers over 9,007,199,254,740,992; for instance, 1234567890123456789 will fail). The former is an easy fix, the latter two not so much.

Regular Expression

The other approach is to test the characters of the string via a regular expression, if your goal is to just allow (say) an optional + followed by either 0 or a string in normal decimal format:

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

Live testbed:

function isNormalInteger(str) {
    return /^\+?(0|[1-9]\d*)$/.test(str);
}
function gid(id) {
    return document.getElementById(id);
}
function test(str, expect) {
    var result = isNormalInteger(str);
    console.log(
        str + ": " +
        (result ? "Yes" : "No") +
        (expect === undefined ? "" : !!expect === !!result ? " <= OK" : " <= ERROR ***")
    );
}
gid("btn").addEventListener(
    "click",
    function() {
        test(gid("text").value);
    },
    false
);
test("1", true);
test("1.23", false);
test("1234567890123", true);
test("1234567890123.1", false);
test("0123", false); // false because we don't handle leading 0s
test(" 123 ", false); // false because we don't handle whitespace
<label>
  String:
  <input id="text" type="text" value="">
<label>
<input id="btn" type="button" value="Check">

How that works:

  1. ^: Match start of string

  2. \+?: Allow a single, optional + (remove this if you don't want to)

  3. (?:...|...): Allow one of these two options (without creating a capture group):

    1. (0|...): Allow 0 on its own...

    2. (...|[1-9]\d*): ...or a number starting with something other than 0 and followed by any number of decimal digits.

  4. $: Match end of string.

If you want to disallow 0 (because it's not positive), the regular expression becomes just /^\+?[1-9]\d*$/ (e.g., we can lose the alternation that we needed to allow 0).

If you want to allow leading zeroes (0123, 00524), then just replace the alternation (?:0|[1-9]\d*) with \d+

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

If you want to allow whitespace, add \s* just after ^ and \s* just before $.

Note for when you convert that to a number: On modern engines it would probably be fine to use +str or Number(str) to do it, but older ones might extend those in a non-standard (but formerly-allowed) way that says a leading zero means octal (base 8), e.g "010" => 8. Once you've validated the number, you can safely use parseInt(str, 10) to ensure that it's parsed as decimal (base 10). parseInt would ignore garbage at the end of the string, but we've ensured there isn't any with the regex.

查看更多
登录 后发表回答