Перевірте, що рядок є натуральним числом


200

Я хотів би, щоб найпростіший тест на відмову перевірив, чи є рядок у JavaScript цілим числом.

isNaN(str)повертає true для всіх видів не цілих значень і parseInt(str)повертає цілі числа для плавких рядків, як-от "2.5". І я також не хочу використовувати плагін jQuery.


7
Ви дозволяєте "+2"? Як щодо "0,1e1"? Як щодо "1.0000"?
Фрогз

isNaN()Функція поводиться так , як це робить тому , що поняття Not a Numberмає дуже специфічне значення в специфікації IEEE 794 з плаваючою точкою. Він не має наміру дати відповідь на просте розмовне запитання: "це значення не число?"
Поні

3
Питання до крайності неясне. Ви не можете перевірити, що "рядок є цілим числом", оскільки такого немає - жоден об'єкт не може бути одночасно рядком і числом. Ви, мабуть, мали на увазі "як перевірити, чи є рядок дійсним поданням цілого числа", але для того, щоб відповісти на це, нам потрібно знати, про яку мову чи "культуру" ви говорите. Наприклад, ٢‎٣٤або MCMXIXобидва дійсні цілі уявлення, але я не думаю, що ви шукаєте код, який би міг їх розібрати. Чи можете ви вказати, які формати чисел ви будете підтримувати, оскільки люди здаються розгубленими з цього приводу.
georg

5
Я думаю, що "розпливчастість до крайності" сама по собі трохи екстремальна; але все одно ... Контекст - це перевірка поля введення кількості на кошику для покупок, який використовується в англомовній країні, тому лише західні цифри. Під "позитивом" я мав на увазі більше нуля. Я б прийняв таке: "+2" так, "0.1e1" ні, "1.000" впевнений, чому ні. Однак, якщо ви можете надати відповідь, яку можна налаштувати на включення / виключення цих різних спеціалізованих сценаріїв, я обіцяю отримати додаткові результати (і я впевнений, що і інші).
Мік Бірн

Відповіді:


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: Перевірте, що це позитивно.

Зауважте, що це не вдається для введення даних "+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*безпосередньо перед цим $.

Зверніть увагу на те, коли ви перетворюєте це на число: На сучасних двигунах це, мабуть, буде непогано використовувати +strабо Number(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

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

DEMO: 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 % (...)перевіряє, чи значення не плаваюче - тут (...)(див. 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

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


Попередня версія:

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

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


Спробуйте порожню рядок або велику кількість, наприклад 1290000981231123.1 - jsfiddle.net/5UCy4/1
Ніко,

@gdoron Те саме, що ~~val, відрізаючи дробову частину. Це трохи швидше, оскільки робить одну побітну операцію замість двох.
VisioN

Чудова відповідь. Особисто я хотів би бути трохи докладнішим для читабельності(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Рамі Наср

true, false, 0xFF, а інші значення здійснюють його isPositiveIntegerбез виявлення.
Xeoncross

1
Цей навіть обробляє прокладені нулі (добре!). Ви можете додати це до своїх тестів.
Рашак

21

Схоже, регулярний вираз - це шлях:

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

Закрийте, якщо не дозволено "1.0" або ".1e1".
Фрогз

Добре 1290000192379182379123782900192981231 є цілим числом, але воно не відображається саме в рідних номерах JavaScript, тому з регулярним виразом все-таки потрібно зробити числове перетворення і переконатися, що воно працювало.
Поні

Це дуже неточне рішення.
usr

@usr: Я вважаю, що це дозволяє вести 0туди, куди ти зазвичай не розраховував, але здебільшого здається нормальним.
TJ Crowder

Він не перевіряє діапазон не більше 2 ^ 31-1 і не дозволяє арабських цифр. Це злом, не гарне рішення. Найкраще рішення має найбільше відгуків у цьому питанні. Чому б не скористатися цим? Краще в усіх відношеннях.
usr

17

Сучасне рішення, яке працює у вузлі та понад 90% усіх браузерів (крім IE та Opera Mini), полягає у використанні Number.isInteger, після чого проводиться проста позитивна перевірка.

Number.isInteger(x) && x > 0

Це було завершено в ECMAScript 2015 .

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

Поліфіл:

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

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

Ви також можете розширити номер і призначити йому функцію за допомогою прототипу.


1

Якщо ви використовуєте форми HTML5, ви можете використовувати атрибут min="0"для елемента форми <input type="number" />. Це підтримується всіма основними браузерами. Він не залучає Javascript для таких простих завдань, але інтегрований у новий стандарт html. Це задокументовано на https://www.w3schools.com/tags/att_input_min.asp


0

(~~a == a)де aрядок.


1
Це не вдасться до негативних чисел: ~~"-1" == "-1"повернеться true. І ОП запитували лише додатні цілі числа.
Ігор Мілла

1
Також не працює для '' і ''.
neverfox

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.