Проверьте, что строка является положительным целым числом

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оба являются допустимыми целочисленными представлениями, но я не думаю, что вы ищете код, который бы мог их проанализировать. Не могли бы вы указать, какие числовые форматы вы собираетесь поддерживать, поскольку люди, похоже, смущены этим.
Георг
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будет игнорировать мусор в конце строки, но мы убедились, что с регулярным выражением их нет.

TJ Crowder
источник
оба Number(' ')и Number('')return в 0то время как должны вернуться NaNвместо.
неврино
@TJCrowder хорошо, но мне нужно, чтобы строки типа '' 2a '' были как-то отклонены, parseIntвозвращает 2.
неврино
@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

ДЕМО: 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 % (...)проверяет, является ли значение non-float - здесь (...)(см. 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
Нико,
@gdoron Тоже самое ~~val, что отрезать дробную часть. Это немного быстрее, так как выполняет одну побитовую операцию вместо двух.
VisioN
Отличный ответ. Лично я предпочел бы быть немного более многословным для удобства чтения(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Рами Наср
true, false, 0xFFи другие значения делают это isPositiveIntegerбез обнаружения.
Xeoncross
1
Этот даже обрабатывает дополненные нули (хорошо!). Вы можете добавить это к своим тестам.
Рашак
21

Похоже, регулярное выражение это путь:

var isInt = /^\+?\d+$/.test('the string');
Niko
источник
Закрыть, если не разрешены «1.0» или «.1e1».
Phrogz
Ну, 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;
};

Если вам нужно поддерживать ввод, который может быть в виде строки или числа, то вы можете использовать эту функцию, против которой я написал большой набор тестов после того, как все существующие ответы (1/2/2018) не сработали на какой-либо форме ввода.

function isPositiveInteger(v) {
  var i;
  return v && (i = parseInt(v)) && i > 0 && (i === v || ''+i === v);
}
Xeoncross
источник
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;
}
Chango
источник
Я знаю, что это почти дублирует вопрос «Проверка чисел в JavaScript», я прочитал всю эту тему, но я подумал, что вопрос о строковых представлениях целых чисел заслуживает отдельной страницы.
Мик Бирн
2
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

не будет работать, если вы дадите строку типа «0001», хотя

Sebas
источник
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});
USR-бен-питьевой
источник
2

просто

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

console.log(isInteger(1));

Вы также можете расширить Number и назначить ему функцию через прототип.

маниш кумар
источник
1

Если вы используете формы HTML5, вы можете использовать атрибут min="0"для элемента формы <input type="number" />. Это поддерживается всеми основными браузерами. Он не использует Javascript для таких простых задач, но интегрирован в новый стандарт HTML. Это задокументировано на https://www.w3schools.com/tags/att_input_min.asp

mggluscevic
источник
0

(~~a == a)где aстрока

Гас
источник
1
Это не удастся для отрицательных чисел: ~~"-1" == "-1"вернется true. И ОП попросил только натуральные числа.
Игорь Милла
1
Также не работает для '' и ''.
neverfox