Validate that a string is a positive integer

Validate that a string is a positive integer

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.

Solutions/Answers:

Solution 1:

Two answers for you:

  • Based on parsing

  • Regular expression

Note that in both cases, I’ve interpreted “positive integer” to include , even though is not positive. I include notes if you want to disallow .

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

Live testbed:

function isNormalInteger(str) {
    var n = Math.floor(Number(str));
    return String(n) === str && n >= 0;
}
function gid(id) {
  return document.getElementById(id);
}
function test(str, expect) {
  console.log(str + ": " + (isNormalInteger(str) ? "Yes" : "No"));
}
gid("btn").addEventListener(
  "click",
  function() {
    test(gid("text").value);
  },
  false
);
test("1");
test("1.23");
test("1234567890123");
test("1234567890123.1");
<label>
  String:
  <input id="text" type="text" value="">
<label>
<input id="btn" type="button" value="Check">

If you want to disallow , just change >= 0 to > 0.

How that works:

  1. Number(str): Convert str to a number; the number may well have a fractional portion, or may be NaN.

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

  3. 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..)

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

  5. n >= 0: Check that it’s positive.

Related:  Can scripts be inserted with innerHTML?

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 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) {
  console.log(str + ": " + (isNormalInteger(str) ? "Yes" : "No"));
}
gid("btn").addEventListener(
  "click",
  function() {
    test(gid("text").value);
  },
  false
);
test("1");
test("1.23");
test("1234567890123");
test("1234567890123.1");
<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 on its own…

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

  4. $: Match end of string.

If you want to disallow (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 ).

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

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.

Related:  Is there any way to center text with jsPDF?

Solution 2:

Solution 1

If we consider a JavaScript integer to be a value of maximum 4294967295 (i.e. Math.pow(2,32)-1), then the following short solution will perfectly work:

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

DESCRIPTION:

  1. Zero-fill right shift operator does three important things:
    • truncates decimal part
      • 123.45 >>> 0 === 123
    • does the shift for negative numbers
      • -1 >>> 0 === 4294967295
    • “works” in range of MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloat does correct parsing of string numbers (setting NaN for non numeric strings)

TESTS:

"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

DEMO: http://jsfiddle.net/5UCy4/37/


Solution 2

Another way is good for all numeric values which are valid up to Number.MAX_VALUE, i.e. to about 1.7976931348623157e+308:

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

DESCRIPTION:

  1. !isNaN(parseFloat(n)) is used to filter pure string values, e.g. "", " ", "string";
  2. 0 <= ~~n filters negative and large non-integer values, e.g. "-40.1", "129000098131766699";
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n) returns true if value is both numeric and positive;
  4. 0 === n % (...) checks if value is non-float — here (...) (see 3) is evaluated as in case of false, and as 1 in case of true.

TESTS:

"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

DEMO: http://jsfiddle.net/5UCy4/14/

Related:  Catching any click performed using jQuery

The previous version:

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

DEMO: http://jsfiddle.net/5UCy4/2/

Solution 3:

Looks like a regular expression is the way to go:

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

Solution 4:

The modern solution that works in node and across over 90% of all browsers (except IE and Opera Mini) is to use Number.isInteger followed by a simple positive check.

Number.isInteger(x) && x > 0

This was finalized in ECMAScript 2015.

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

The Polyfil is:

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

If you need to support input that might be in string or number form then you can use this function I wrote a large test suite against after all the existing answers (2/1/2018) failed on some form of input.

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

Solution 5:

This is almost a duplicate question fo this one:

Validate decimal numbers in JavaScript – IsNumeric()

It’s answer is:

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

so, a positive integer would be:

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

Solution 6:

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

won’t work if you give a string like ‘0001’ though