Перевірка десяткових чисел у JavaScript - IsNumeric ()


2376

Який найчистіший і найефективніший спосіб перевірити десяткові числа в JavaScript?

Бонусні бали за:

  1. Чіткість. Розчин повинен бути чистим і простим.
  2. Крос-платформа.

Тестові приклади:

01. IsNumeric('-1')      => true
02. IsNumeric('-1.5')    => true
03. IsNumeric('0')       => true
04. IsNumeric('0.42')    => true
05. IsNumeric('.42')     => true
06. IsNumeric('99,999')  => false
07. IsNumeric('0x89f')   => false
08. IsNumeric('#abcdef') => false
09. IsNumeric('1.2.3')   => false
10. IsNumeric('')        => false
11. IsNumeric('blah')    => false

256
Просто примітка 99 999 - це дійсне число у Франції, це те саме, що 99,999 у форматі uk / us, тож якщо ви читаєте в рядку з, скажімо, форми введення, то 99,999 може бути правдою.
Re0sless


79
Десяткові коми - це стандарт у всій Європі та Росії (крім Великобританії)
Кальмарій

90
jQuery 1.7 ввів функцію jQuery.isNumericутиліти: api.jquery.com/jQuery.isNumeric
Ates Goral

24
jQuery.isNumericне вдасться до семи тестового випадку ОП ( IsNumeric('0x89f') => *false*). Я не впевнений, чи згоден я з цим тестовим випадком.
Тім Ленер

Відповіді:


2898

@ Відповідь Джоеля досить близька, але вона не вдасться в таких випадках:

// Whitespace strings:
IsNumeric(' ')    == true;
IsNumeric('\t\t') == true;
IsNumeric('\n\r') == true;

// Number literals:
IsNumeric(-1)  == false;
IsNumeric(0)   == false;
IsNumeric(1.1) == false;
IsNumeric(8e5) == false;

Деякий час тому мені довелося реалізувати IsNumericфункцію, щоб з'ясувати, чи містить змінна числове значення, незалежно від її типу , це може бутиString числове значення (я мав би враховувати також експоненціальне позначення тощо), Numberоб'єкт, на цю функцію може бути передано практично все, я не міг робити жодних припущень щодо типу, опікуючись типом примусу (наприклад, +true == 1;але trueне слід вважати таким "numeric").

Думаю, варто поділитися цим набором тестів +30 одиниць, зробленим на численні реалізації функцій, а також поділитися тим, який пройшов усі мої тести:

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

PS isNaN & isFinite мають заплутану поведінку через вимушене перетворення в число. У ES6, число.isNaN і число.isFinite ці проблеми б . Майте це на увазі під час їх використання.


Оновлення : Ось як jQuery робить це зараз (2.2-стабільний) :

isNumeric: function(obj) {
    var realStringObj = obj && obj.toString();
    return !jQuery.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
}

Оновлення : кутовий 4.3 :

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}

26
це не вдається з іншими локалями, де ми використовуємо десяткові коми, але додаємо `n = n.replace (/, /,". "); ' перед поверненням, щоб виправити це.
Золтан Ленгель

5
@RobG, що поведінка є навмисним, 2e308 > Number.MAX_VALUEтак як 2e308 == Infinity. Якщо ви хочете, щоб функція, яка повертає trueтакож позитивні та негативні значення нескінченності, перевірте функцію №2 у тестовому наборі . Ура.
CMS

39
До речі, одиничні тести зараз використовуються проектом jQuery
CMS

7
jQuery тепер також використовує цю реалізацію.
RichardTowers

4
Рішення тут - просто використовувати JQuery. Зараз вони ще краще реалізують це: github.com/jquery/jquery/blob/master/src/core.js#L230
Роберт Массайолі

337

Arrrgh! Не слухайте відповіді на регулярний вираз. RegEx є пристрасним до цього, і я не кажу лише про продуктивність. Настільки легко зробити тонкі, неможливо помітити помилки своїм регулярним виразом.

Якщо ви не можете використовувати isNaN(), це має працювати набагато краще:

function IsNumeric(input)
{
    return (input - 0) == input && (''+input).trim().length > 0;
}

Ось як це працює:

(input - 0)Вираз змушує JavaScript робити тип примус від вхідного значення; спочатку його слід інтерпретувати як число для операції віднімання. Якщо це перетворення в число не вдасться, вираз призведе до NaN. Цей числовий результат порівнюється з початковим значенням, яке ви передали. Оскільки ліва частина тепер є числовою, знову застосовується примус. Тепер, коли введення з обох сторін було примусоване до одного типу з одного і того ж вихідного значення, ви вважаєте, що вони завжди повинні бути однаковими (завжди істинними). Однак є спеціальне правило, яке говорить NaN, що ніколи не дорівнюєNaN , і тому значення, яке неможливо перетворити на число (і лише значення, які не можна перетворити на числа), призведе до помилки.

Перевірка довжини призначена для окремого випадку, що включає порожні рядки. Також зауважте, що він падає на ваш тест 0x89f, але це тому, що в багатьох середовищах це нормальний спосіб визначити число буквальне. Якщо ви хочете спіймати цей конкретний сценарій, ви можете додати додатковий чек. Ще краще, якщо це ваша причина не використовувати, isNaN()тоді просто оберніть свою власну функцію, isNaN()що також може зробити додаткову перевірку.

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


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

Запуск одиничних тестів з новим кодом, і він не спрацьовує нескінченності та булевих літералах, і єдиний час, який повинен виникнути проблеми, - це якщо ви генеруєте код (дійсно, хто вводить літерал і перевіряє, чи є він чисельним? Ви повинні знати ), і це був би якийсь дивний код для створення.

Але, знову ж таки, єдина причина, яка коли-небудь використовувати це - це якщо вам чомусь доводиться уникатиNaN ().


28
Це не вдається в рядках пробілів, наприклад IsNumeric(' '), IsNumeric('\n\t')і т.д., всі повертаютьсяtrue
Crescent Fresh

29
Він також втратить на Numberлітерали IsNumeric(5) == false;перевірити набір модульних тестів , я відповідав, ця функція є номер 16на наборі тестів. stackoverflow.com/questions/18082/…
CMS

20
Я не можу повірити, що ніхто не вказав на використання регулярного виразу (заміни) після попередження про невживання регулярних виразів ... Зрозуміло, заміна пробілів простіша за розбір числа, але все одно, безумовно, "пристрасна".
Патрік М

1
@Oriol Це велика проблема ... без виправлень безпеки після цієї дати вимкнення XP не повинно бути пріоритетним завданням.
Joel Coehoorn

1
@ Oriol XP чи ні, якщо ви використовуєте IE8 або нижче, ви використовуєте жахливо застаріле програмне забезпечення. Затверджений XP не може запускати IE9 +, тому використовуйте Chrome або FF. Люди, які жили в минулому за допомогою IE8, є основою існування багатьох веб-розробників. Якби я міг повернути час, який я витратив, переконуючись, що ідеально хороший код також працює в IE8 ... Мені взяти код, який працює у FF та Chrome, і виправити його для запуску в IE8 - це практично так само, як взяти виконуваний Windows 8 і переконайтесь, що він працює однаково в Windows 3.1.
chiliNUT

70

Цей спосіб, здається, працює добре:

function IsNumeric(input){
    var RE = /^-{0,1}\d*\.{0,1}\d+$/;
    return (RE.test(input));
}

В одному рядку:

const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);

І протестувати це:

const IsNumeric = (num) => /^-{0,1}\d*\.{0,1}\d+$/.test(num);
    
    function TestIsNumeric(){
        var results = ''
        results += (IsNumeric('-1')?"Pass":"Fail") + ": IsNumeric('-1') => true\n";
        results += (IsNumeric('-1.5')?"Pass":"Fail") + ": IsNumeric('-1.5') => true\n";
        results += (IsNumeric('0')?"Pass":"Fail") + ": IsNumeric('0') => true\n";
        results += (IsNumeric('0.42')?"Pass":"Fail") + ": IsNumeric('0.42') => true\n";
        results += (IsNumeric('.42')?"Pass":"Fail") + ": IsNumeric('.42') => true\n";
        results += (!IsNumeric('99,999')?"Pass":"Fail") + ": IsNumeric('99,999') => false\n";
        results += (!IsNumeric('0x89f')?"Pass":"Fail") + ": IsNumeric('0x89f') => false\n";
        results += (!IsNumeric('#abcdef')?"Pass":"Fail") + ": IsNumeric('#abcdef') => false\n";
        results += (!IsNumeric('1.2.3')?"Pass":"Fail") + ": IsNumeric('1.2.3') => false\n";
        results += (!IsNumeric('')?"Pass":"Fail") + ": IsNumeric('') => false\n";
        results += (!IsNumeric('blah')?"Pass":"Fail") + ": IsNumeric('blah') => false\n";
        
        return results;
    }

console.log(TestIsNumeric());
.as-console-wrapper { max-height: 100% !important; top: 0; }

Я запозичив цей регекс у http://www.codetoad.com/javascript/isnumeric.asp . Пояснення:

/^ match beginning of string
-{0,1} optional negative sign
\d* optional digits
\.{0,1} optional decimal point
\d+ at least one digit
$/ match end of string

1
// ТАКОЖ ДОБАВЛЕНО ДО ВАШИХ результатів тесту + = (! IsNumeric ('-')? "Pass": "Fail") + ": IsNumeric ('-') => false \ n"; results + = (! IsNumeric ('01 ')? "Pass": "Fail") + ": IsNumeric ('01') => false \ n"; results + = (! IsNumeric ('- 01')? "Pass": "Fail") + ": IsNumeric ('- 01') => false \ n"; Результати + = (! IsNumeric ('000')? "Pass": "Fail") + ": IsNumeric ('000') => false \ n";
День

що це робить? / ^ - {0,1} \ d * \. {0,1} \ d + $ /
зателефонуй мені

може "{0,1}" замінити на "?", тож ваш регулярний вигляд буде виглядати так: /^-?\d*\.?\d+$/?
Хмара

приємно і просто.
перерва

53

Yahoo! Користувальницький інтерфейс використовує це:

isNumber: function(o) {
    return typeof o === 'number' && isFinite(o);
}

25
Це більше перевірка типу змінної на відміну від вмісту числа. Він також вийде з числа, створених за допомогою new Number(1).
alex

4
Як каже Алекс, це фактично не відповідає на поставлене питання, оскільки це не вдасться, якщо o = "1001".
Справа

50
function IsNumeric(num) {
     return (num >=0 || num < 0);
}

Це також працює для номерів типу 0x23.


29
IsNumeric(''), IsNumeric(' '), IsNumeric(true), IsNumeric(false), IsNumeric(null)Повернути trueзамість false.
Оріол

49

Прийнята відповідь зазнала невдачі у вашому тесті №7, і я думаю, це тому, що ви передумали. Отже, це відповідь на прийняту відповідь, з якою у мене виникли проблеми.

Під час деяких проектів мені потрібно було перевірити деякі дані та бути максимально впевненими, що це числове значення javascript, яке можна використовувати в математичних операціях.

jQuery та деякі інші бібліотеки javascript вже включають таку функцію, яку зазвичай називають isNumeric. Існує також публікація про stackoverflow , яка широко прийнята як відповідь, та сама загальна процедура, яку використовують вищезгадані бібліотеки.

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

По-перше, наведений вище код повернеться істинним, якби аргумент був масивом довжиною 1, і цей єдиний елемент був типу, який вважається числовим за вищенаведеною логікою. На мою думку, якщо це масив, то він не є числовим.

Щоб полегшити цю проблему, я додав чек для знижки масивів з логіки

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n);
}

Звичайно, ви можете також використовувати Array.isArrayjquery $.isArrayабо прототип Object.isArrayзамістьObject.prototype.toString.call(n) !== '[object Array]'

Моє друге питання полягало в тому, що негативні шістнадцяткові цілі цілі літеральні рядки ("-0xA" -> -10) не вважаються числовими. Однак позитивні шістнадцяткові цілочислові рядкові рядки ("0xA" -> 10) трактуються як числові. Мені потрібно було обидва, щоб бути дійсними числовими.

Потім я змінив логіку, щоб врахувати це.

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

Якщо ви турбуєтесь про створення регулярного виразу щоразу, коли функція викликається, ви можете переписати її в межах закриття, щось подібне

var isNumber = (function () {
  var rx = /^-/;

  return function (n) {
      return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(rx, ''));
  };
}());

Потім я взяв CMS +30 тестових випадків і клонував тестування на jsfiddle, додав мої додаткові тестові випадки та моє вище описане рішення.

Він може не замінити широко прийняту / використовувану відповідь, але якщо це більше того, що ви очікуєте в результаті своєї функції isNumeric, то, сподіваємось, це буде корисною.

EDIT: Як зазначав Бергі , існують й інші можливі об'єкти, які можна вважати числовими, і їх було б краще додати до списку, ніж до чорного списку. Зважаючи на це, я б додав до критеріїв.

Я хочу, щоб моя isNumeric функція враховувала лише числа чи рядки

Зважаючи на це, було б краще використовувати

function isNumber(n) {
  return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

Випробування розчинів

var testHelper = function() {

  var testSuite = function() {
    test("Integer Literals", function() {
      ok(isNumber("-10"), "Negative integer string");
      ok(isNumber("0"), "Zero string");
      ok(isNumber("5"), "Positive integer string");
      ok(isNumber(-16), "Negative integer number");
      ok(isNumber(0), "Zero integer number");
      ok(isNumber(32), "Positive integer number");
      ok(isNumber("040"), "Octal integer literal string");
      ok(isNumber(0144), "Octal integer literal");
      ok(isNumber("-040"), "Negative Octal integer literal string");
      ok(isNumber(-0144), "Negative Octal integer literal");
      ok(isNumber("0xFF"), "Hexadecimal integer literal string");
      ok(isNumber(0xFFF), "Hexadecimal integer literal");
      ok(isNumber("-0xFF"), "Negative Hexadecimal integer literal string");
      ok(isNumber(-0xFFF), "Negative Hexadecimal integer literal");
    });

    test("Foating-Point Literals", function() {
      ok(isNumber("-1.6"), "Negative floating point string");
      ok(isNumber("4.536"), "Positive floating point string");
      ok(isNumber(-2.6), "Negative floating point number");
      ok(isNumber(3.1415), "Positive floating point number");
      ok(isNumber(8e5), "Exponential notation");
      ok(isNumber("123e-2"), "Exponential notation string");
    });

    test("Non-Numeric values", function() {
      equals(isNumber(""), false, "Empty string");
      equals(isNumber("        "), false, "Whitespace characters string");
      equals(isNumber("\t\t"), false, "Tab characters string");
      equals(isNumber("abcdefghijklm1234567890"), false, "Alphanumeric character string");
      equals(isNumber("xabcdefx"), false, "Non-numeric character string");
      equals(isNumber(true), false, "Boolean true literal");
      equals(isNumber(false), false, "Boolean false literal");
      equals(isNumber("bcfed5.2"), false, "Number with preceding non-numeric characters");
      equals(isNumber("7.2acdgs"), false, "Number with trailling non-numeric characters");
      equals(isNumber(undefined), false, "Undefined value");
      equals(isNumber(null), false, "Null value");
      equals(isNumber(NaN), false, "NaN value");
      equals(isNumber(Infinity), false, "Infinity primitive");
      equals(isNumber(Number.POSITIVE_INFINITY), false, "Positive Infinity");
      equals(isNumber(Number.NEGATIVE_INFINITY), false, "Negative Infinity");
      equals(isNumber(new Date(2009, 1, 1)), false, "Date object");
      equals(isNumber(new Object()), false, "Empty object");
      equals(isNumber(function() {}), false, "Instance of a function");
      equals(isNumber([]), false, "Empty Array");
      equals(isNumber(["-10"]), false, "Array Negative integer string");
      equals(isNumber(["0"]), false, "Array Zero string");
      equals(isNumber(["5"]), false, "Array Positive integer string");
      equals(isNumber([-16]), false, "Array Negative integer number");
      equals(isNumber([0]), false, "Array Zero integer number");
      equals(isNumber([32]), false, "Array Positive integer number");
      equals(isNumber(["040"]), false, "Array Octal integer literal string");
      equals(isNumber([0144]), false, "Array Octal integer literal");
      equals(isNumber(["-040"]), false, "Array Negative Octal integer literal string");
      equals(isNumber([-0144]), false, "Array Negative Octal integer literal");
      equals(isNumber(["0xFF"]), false, "Array Hexadecimal integer literal string");
      equals(isNumber([0xFFF]), false, "Array Hexadecimal integer literal");
      equals(isNumber(["-0xFF"]), false, "Array Negative Hexadecimal integer literal string");
      equals(isNumber([-0xFFF]), false, "Array Negative Hexadecimal integer literal");
      equals(isNumber([1, 2]), false, "Array with more than 1 Positive interger number");
      equals(isNumber([-1, -2]), false, "Array with more than 1 Negative interger number");
    });
  }

  var functionsToTest = [

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

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

    function(n) {
      return !isNaN((n));
    },

    function(n) {
      return !isNaN(parseFloat(n));
    },

    function(n) {
      return typeof(n) != "boolean" && !isNaN(n);
    },

    function(n) {
      return parseFloat(n) === Number(n);
    },

    function(n) {
      return parseInt(n) === Number(n);
    },

    function(n) {
      return !isNaN(Number(String(n)));
    },

    function(n) {
      return !isNaN(+('' + n));
    },

    function(n) {
      return (+n) == n;
    },

    function(n) {
      return n && /^-?\d+(\.\d+)?$/.test(n + '');
    },

    function(n) {
      return isFinite(Number(String(n)));
    },

    function(n) {
      return isFinite(String(n));
    },

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

    function(n) {
      return parseFloat(n) == n;
    },

    function(n) {
      return (n - 0) == n && n.length > 0;
    },

    function(n) {
      return typeof n === 'number' && isFinite(n);
    },

    function(n) {
      return !Array.isArray(n) && !isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
    }

  ];


  // Examines the functionsToTest array, extracts the return statement of each function
  // and fills the toTest select element.
  var fillToTestSelect = function() {
    for (var i = 0; i < functionsToTest.length; i++) {
      var f = functionsToTest[i].toString();
      var option = /[\s\S]*return ([\s\S]*);/.exec(f)[1];
      $("#toTest").append('<option value="' + i + '">' + (i + 1) + '. ' + option + '</option>');
    }
  }

  var performTest = function(functionNumber) {
    reset(); // Reset previous test
    $("#tests").html(""); //Clean test results
    isNumber = functionsToTest[functionNumber]; // Override the isNumber global function with the one to test
    testSuite(); // Run the test

    // Get test results
    var totalFail = 0;
    var totalPass = 0;
    $("b.fail").each(function() {
      totalFail += Number($(this).html());
    });
    $("b.pass").each(function() {
      totalPass += Number($(this).html());
    });
    $("#testresult").html(totalFail + " of " + (totalFail + totalPass) + " test failed.");

    $("#banner").attr("class", "").addClass(totalFail > 0 ? "fail" : "pass");
  }

  return {
    performTest: performTest,
    fillToTestSelect: fillToTestSelect,
    testSuite: testSuite
  };
}();


$(document).ready(function() {
  testHelper.fillToTestSelect();
  testHelper.performTest(0);

  $("#toTest").change(function() {
    testHelper.performTest($(this).children(":selected").val());
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script src="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.js" type="text/javascript"></script>
<link href="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.css" rel="stylesheet" type="text/css">
<h1>isNumber Test Cases</h1>

<h2 id="banner" class="pass"></h2>

<h2 id="userAgent">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11</h2>

<div id="currentFunction"></div>

<div id="selectFunction">
  <label for="toTest" style="font-weight:bold; font-size:Large;">Select function to test:</label>
  <select id="toTest" name="toTest">
  </select>
</div>

<div id="testCode"></div>

<ol id="tests">
  <li class="pass">
    <strong>Integer Literals <b style="color:black;">(0, 10, 10)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative integer string</li>

      <li class="pass">Zero string</li>

      <li class="pass">Positive integer string</li>

      <li class="pass">Negative integer number</li>

      <li class="pass">Zero integer number</li>

      <li class="pass">Positive integer number</li>

      <li class="pass">Octal integer literal string</li>

      <li class="pass">Octal integer literal</li>

      <li class="pass">Hexadecimal integer literal string</li>

      <li class="pass">Hexadecimal integer literal</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Foating-Point Literals <b style="color:black;">(0, 6, 6)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative floating point string</li>

      <li class="pass">Positive floating point string</li>

      <li class="pass">Negative floating point number</li>

      <li class="pass">Positive floating point number</li>

      <li class="pass">Exponential notation</li>

      <li class="pass">Exponential notation string</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Non-Numeric values <b style="color:black;">(0, 18, 18)</b></strong>

    <ol style="display: none;">
      <li class="pass">Empty string: false</li>

      <li class="pass">Whitespace characters string: false</li>

      <li class="pass">Tab characters string: false</li>

      <li class="pass">Alphanumeric character string: false</li>

      <li class="pass">Non-numeric character string: false</li>

      <li class="pass">Boolean true literal: false</li>

      <li class="pass">Boolean false literal: false</li>

      <li class="pass">Number with preceding non-numeric characters: false</li>

      <li class="pass">Number with trailling non-numeric characters: false</li>

      <li class="pass">Undefined value: false</li>

      <li class="pass">Null value: false</li>

      <li class="pass">NaN value: false</li>

      <li class="pass">Infinity primitive: false</li>

      <li class="pass">Positive Infinity: false</li>

      <li class="pass">Negative Infinity: false</li>

      <li class="pass">Date object: false</li>

      <li class="pass">Empty object: false</li>

      <li class="pass">Instance of a function: false</li>
    </ol>
  </li>
</ol>

<div id="main">
  This page contains tests for a set of isNumber functions. To see them, take a look at the source.
</div>

<div>
  <p class="result">Tests completed in 0 milliseconds.
    <br>0 tests of 0 failed.</p>
</div>


2
Це, на мій погляд, найбільш захищена функція; останній. Прийнята відповідь охоплює, мабуть, 99,99% усіх випадків, але цей, мабуть, 100% а) випадків з невеликими накладними витратами.
Самуїл

Ви забули про літерал "99,999" Foating-Point. Це дійсне число у всій Європі, крім Великобританії
Андрій Горда

Це не було забуто, це було не те, що я вважав числовим у значенні номерів Javascript, також ОП заявивIsNumeric('99,999') => false
Xotic750

34

Так, вбудований isNaN(object)модуль буде набагато швидшим, ніж будь-який синтаксичний аналіз, тому що він є вбудованим та компільованим, а не інтерпретованим на ходу.

Хоча результати дещо відрізняються від того, що ви шукаєте ( спробуйте ):

                                              // IS NUMERIC
document.write(!isNaN('-1') + "<br />");      // true
document.write(!isNaN('-1.5') + "<br />");    // true
document.write(!isNaN('0') + "<br />");       // true
document.write(!isNaN('0.42') + "<br />");    // true
document.write(!isNaN('.42') + "<br />");     // true
document.write(!isNaN('99,999') + "<br />");  // false
document.write(!isNaN('0x89f') + "<br />");   // true
document.write(!isNaN('#abcdef') + "<br />"); // false
document.write(!isNaN('1.2.3') + "<br />");   // false
document.write(!isNaN('') + "<br />");        // true
document.write(!isNaN('blah') + "<br />");    // false

18

Використовуйте функцію isNaN. Я вважаю, що якщо ви перевірите на !isNaN(yourstringhere)це, він справно працює в будь-якій з цих ситуацій.


Примітка:! IsNaN (null) == вірно, оскільки Number (null) == 0
Jonathan Lonowski

якщо (! (x == null || isNaN (x))) попередження ("isNumeric"); // Але це рішення приймає 0x40, тому воно все ще не є тим, чого хотіла оп.
десь

Зауважте, що isNaN ("нескінченність") === помилково, що, мабуть, теж не те, що ви хочете (але також не відбудеться в реальному житті).
Ерік Гесселінк

16

Оскільки jQuery 1.7, ви можете використовувати jQuery.isNumeric():

$.isNumeric('-1');      // true
$.isNumeric('-1.5');    // true
$.isNumeric('0');       // true
$.isNumeric('0.42');    // true
$.isNumeric('.42');     // true
$.isNumeric('0x89f');   // true (valid hexa number)
$.isNumeric('99,999');  // false
$.isNumeric('#abcdef'); // false
$.isNumeric('1.2.3');   // false
$.isNumeric('');        // false
$.isNumeric('blah');    // false

Просто зауважте, що на відміну від того, що ви сказали, 0x89fє дійсним числом (гекса)


ОП хоче дійсне десяткове число, тому jQuery isNumeric не відповідає. Він також не вдається для дуже великої кількості.
RobG

13

Це можна зробити без RegExp як

function IsNumeric(data){
    return parseFloat(data)==data;
}

5
Якщо ми використовуємо ==, воно повернеться істинним навіть для чисел, представлених у вигляді рядків. Тож "42" вважатиметься дійсним числом у разі "==" і вважатиметься недійсним у разі ===
Aquatic

це повертає значення "-0.", "-.0", ".0" та "0."
Янус Трольсен


8
return (input - 0) == input && input.length > 0;

не працювало для мене. Коли я поставив попередження і перевірив, input.lengthбув undefined. Я думаю, що немає властивості перевіряти цілу довжину. Так що я і робив

var temp = '' + input;
return (input - 0) == input && temp.length > 0;

Це добре працювало.


7

Якщо я не помиляюся, це повинно відповідати будь-якому дійсному значенню JavaScript, за винятком констант ( Infinity, NaN) та операторів знаків +/ -(оскільки вони насправді не входять до числа, наскільки я це стосується, вони є окремими операторами):

Мені це знадобилося для токенізатора, де надсилання номера в JavaScript для оцінки не було варіантом ... Це, безумовно, не найкоротший можливий регулярний вираз, але я вважаю, що він вловлює всі найтонші тонкощі синтаксису чисел JavaScript.

/^(?:(?:(?:[1-9]\d*|\d)\.\d*|(?:[1-9]\d*|\d)?\.\d+|(?:[1-9]\d*|\d)) 
(?:[e]\d+)?|0[0-7]+|0x[0-9a-f]+)$/i

Дійсні номери включатимуть:

 - 0
 - 00
 - 01
 - 10
 - 0e1
 - 0e01
 - .0
 - 0.
 - .0e1
 - 0.e1
 - 0.e00
 - 0xf
 - 0Xf

Недійсне число було б

 - 00e1
 - 01e1
 - 00.0
 - 00x0
 - .
 - .e0

7

Єдина проблема , яку я мав з @ CMS в відповіді є винятком NaNі Нескінченності, які є корисним номером для багатьох ситуацій. Один із способів перевірити на NaN's - це перевірити чисельні значення, які не рівні собі NaN != NaN! Отже, є справді 3 тести, з якими ви хочете мати справу ...

function isNumber(n) {
  n = parseFloat(n);
  return !isNaN(n) || n != n;
}
function isFiniteNumber(n) {
  n = parseFloat(n);
  return !isNaN(n) && isFinite(n);
}    
function isComparableNumber(n) {
  n = parseFloat(n);
  return (n >=0 || n < 0);
}

isFiniteNumber('NaN')
false
isFiniteNumber('OxFF')
true
isNumber('NaN')
true
isNumber(1/0-1/0)
true
isComparableNumber('NaN')
false
isComparableNumber('Infinity')
true

Мій isComparableNumber досить близький до ще однієї елегантної відповіді , але обробляє шістнадцяткові та інші рядкові зображення чисел.


6

Для мене це найкращий спосіб:

isNumber : function(v){
   return typeof v === 'number' && isFinite(v);
}

На жаль, це чисельна цифрова перевірка STRICT, яка не зможе отримати жоден рядок, що містить лише цифрові літери, наприклад "0" тощо ...
Арман Макгітарін

6

Я хочу додати наступне:

1. IsNumeric('0x89f') => true
2. IsNumeric('075') => true

Позитивні шістнадцяткові числа починаються з, 0xа негативні шістнадцяткові числа починаються з -0x. Позитивні числа oct починаються з, 0а негативні числа oct починаються з -0. Цей враховує більшу частину згаданого, але включає шістнадцяткові та восьмеричні числа, негативні наукові, нескінченність та видалив десятковий науковий ( 4e3.2недійсний).

function IsNumeric(input){
  var RE = /^-?(0|INF|(0[1-7][0-7]*)|(0x[0-9a-fA-F]+)|((0|[1-9][0-9]*|(?=[\.,]))([\.,][0-9]+)?([eE]-?\d+)?))$/;
  return (RE.test(input));
}

6

Я думаю, що функція parseFloat може виконати всю роботу тут. Функція нижче проходить усі тести на цій сторінці, включаючи isNumeric(Infinity) == true:

function isNumeric(n) {

    return parseFloat(n) == n;
}

Так, я прийшов і до цього висновку. Мені також дуже подобається спосіб обробки масивів за допомогою цього методу; масив з єдиним значенням вважається цією цінністю, але все інше не вдається: IsNumeric([3]) == true; IsNumeric([]) == false; IsNumeric([3, 4]) == false; Але я думаю, це справа смаку!
Марк Бірбек

4

Пара тестів, додати:

IsNumeric('01.05') => false
IsNumeric('1.') => false
IsNumeric('.') => false

Я придумав це:

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

Розчин охоплює:

  • Необов’язковий негативний знак на початку
  • Один нуль, або одна чи більше цифр, що не починаються з 0, або нічого, якщо наступний період
  • Період, за яким слідує 1 або більше чисел

4

Ціле значення можна перевірити:

function isNumeric(value) {
    var bool = isNaN(+value));
    bool = bool || (value.indexOf('.') != -1);
    bool = bool || (value.indexOf(",") != -1);
    return !bool;
};

Цей спосіб простіше і швидше! Всі тести перевірені!


4

Ось трохи покращена версія lil (мабуть, найшвидший вихід там), яку я використовую замість точного варіанту jQuery, я дійсно не знаю, чому вони не використовують цю:

function isNumeric(val) {
    return !isNaN(+val) && isFinite(val);
}

Недолік версії JQuery є те , що якщо ви передаєте рядок з провідними і замикаючими числовими буквами як витягне цифрову частину і повернути 123, АЛЕ, другий охоронець не зможе в будь-якому випадку. З одинарним оператором він загине на першому гвардії, оскільки + кидає NaN для таких гібридів :) Невелика продуктивність, але я думаю, що це суттєвий семантичний виграш."123abc"parseFloat | parseIntisFinite+


2
Остерігайтеся, щоб унарний знак "+" викликав valueOf () на об'єкті - див. Цю jsfiddle . Також це також не вдається для провідних пробілів, як і ведуча відповідь.
earcam

3

Моє рішення,

function isNumeric(input) {
    var number = /^\-{0,1}(?:[0-9]+){0,1}(?:\.[0-9]+){0,1}$/i;
    var regex = RegExp(number);
    return regex.test(input) && input.length>0;
}

Здається, це працює у будь-якій ситуації, але я можу помилитися.


Цей регулярний вираз буде менш заплутаним, якщо ви не зайвим чином уникаєте символів, використовуйте ?для {0,1}і \dдля [0-9]. Крім того, +а потім загорнувши його (?:){0,1}, ви можете також використовувати *і забути (не) групи захоплення.
alex


3

Це має спрацювати. Деякі з функцій, наданих тут, є помилковими, також повинні бути швидшими, ніж будь-які інші функції тут.

        function isNumeric(n)
        {
            var n2 = n;
            n = parseFloat(n);
            return (n!='NaN' && n2==n);
        }

Пояснили:

Створіть копію самого себе, потім перетворіть число у флоат, потім порівняйте себе з початковим числом, якщо це все-таки число (чи це ціле чи плаваюче), і збігається з оригінальним числом, це означає, що це дійсно число.

Він працює як з числовими рядками, так і з простими числами. Не працює з шістнадцятковими числами.

Попередження: використовуйте на свій страх і ризик, жодних гарантій.


4
використовуйте на свій страх і ризик, ніяких гарантій я б не використовував код, про який автор не впевнений;)
alex

1
@ Алекс, Принаймні, маєш власну думку про речі. Не просто критикуйте весь час.
Стюарт Мбофана

3

Жодна з відповідей не повертається falseдо порожніх рядків, виправлення для цього ...

function is_numeric(n)
{
 return (n != '' && !isNaN(parseFloat(n)) && isFinite(n));
}

3

Щоб перевірити, чи містить змінна дійсне число, а не лише рядок, схожий на число Number.isFinite(value).

Це частина мови з ES2015

Приклади:

Number.isFinite(Infinity)   // false
Number.isFinite(NaN)        // false
Number.isFinite(-Infinity)  // false

Number.isFinite(0)          // true
Number.isFinite(2e64)       // true

Number.isFinite('0')        // false
Number.isFinite(null)       // false

1
Я б здогадався, що багато людей звертаються до цього питання для розбору вводу користувача, який, як правило, є рядком . Ця відповідь не відповідає в тих випадках, як ви правильно перераховуєте в прикладах, наприкладNumber.isFinite('0') -> false
Майкл Харен

Ви абсолютно праві. Я намагався зробити це чітким фронтом.
adius

3
function inNumeric(n){
   return Number(n).toString() === n;
}

Якщо n числовий Number(n), поверне числове значення і toString()поверне його до рядка. Але якщо n не числове значення Number(n)повернеться, NaNто воно не збігатиметься з оригіналомn


Хоча цей фрагмент коду може вирішити питання, зокрема пояснення дійсно допомагає покращити якість вашої публікації. Пам’ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду. Будь ласка, намагайтеся не переповнювати свій код пояснювальними коментарями, оскільки це зменшує читабельність і коду, і пояснень!
Goodbye StackExchange

2

Я усвідомлюю, що на це відповіли багато разів, але нижче - гідний кандидат, який може бути корисним у деяких сценаріях.

слід зазначити, що він передбачає, що ".42" НЕ є числом, а "4." НЕ число, тому це слід враховувати.

function isDecimal(x) {
  return '' + x === '' + +x;
}

function isInteger(x) {
  return '' + x === '' + parseInt(x);
}

isDecimalПроходить наступний тест:

function testIsNumber(f) {
  return f('-1') && f('-1.5') && f('0') && f('0.42')
    && !f('.42') && !f('99,999') && !f('0x89f')
    && !f('#abcdef') && !f('1.2.3') && !f('') && !f('blah');
}

Ідея тут полягає в тому, що кожне число або ціле число має одне «канонічне» рядкове подання, і кожне неканонічне подання має бути відхилено. Тож ми кидаємо на число і назад, і дивимося, чи є результат оригінальним рядком.

Чи корисні вам ці функції, залежить від випадку використання. Однією з особливостей є те, що окремі рядки представляють окремі числа (якщо обидва проходять isNumber()тест).

Це актуально, наприклад, для чисел як імен властивостей об'єкта.

var obj = {};
obj['4'] = 'canonical 4';
obj['04'] = 'alias of 4';
obj[4];  // prints 'canonical 4' to the console.

2

knockoutJs Вбудувати функції перевірки бібліотеки

Розширюючи його, поле отримують валідацію

1) число

self.number = ko.observable(numberValue).extend ({число: правда}) ;

TestCase

numberValue = '0.0'    --> true
numberValue = '0'      --> true
numberValue = '25'     --> true
numberValue = '-1'     --> true
numberValue = '-3.5'   --> true
numberValue = '11.112' --> true
numberValue = '0x89f'  --> false
numberValue = ''       --> false
numberValue = 'sfsd'   --> false
numberValue = 'dg##$'  --> false

2) цифра

self.number = ko.observable(numberValue).extend ({цифра: правда}) ;

TestCase

numberValue = '0'      --> true
numberValue = '25'     --> true
numberValue = '0.0'    --> false
numberValue = '-1'     --> false
numberValue = '-3.5'   --> false
numberValue = '11.112' --> false
numberValue = '0x89f'  --> false
numberValue = ''       --> false
numberValue = 'sfsd'   --> false
numberValue = 'dg##$'  --> false

3) хв і макс

self.number = ko.observable(numberValue).extend ({min: 5}). Extension ({max: 10}) ;

Це поле приймає значення лише від 5 до 10

TestCase

numberValue = '5'    --> true
numberValue = '6'    --> true
numberValue = '6.5'  --> true
numberValue = '9'    --> true
numberValue = '11'   --> false
numberValue = '0'    --> false
numberValue = ''    --> false

2

Якщо вам потрібно перевірити спеціальний набір десяткових знаків y, ви можете скористатися цим простим javascript:

http://codesheet.org/codesheet/x1kI7hAD

<input type="text" name="date" value="" pattern="[0-9]){1,2}(\.){1}([0-9]){2}" maxlength="6" placeholder="od npr.: 16.06" onchange="date(this);" />

Javascript:

function date(inputField) {        
  var isValid = /^([0-9]){1,2}(\.){1}([0-9]){2}$/.test(inputField.value);   
  if (isValid) {
    inputField.style.backgroundColor = '#bfa';
  } else {
    inputField.style.backgroundColor = '#fba';
  }
  return isValid;
}

2

isNumeric=(el)=>{return Boolean(parseFloat(el)) && isFinite(el)}

Нічого не відрізняється, але ми можемо використовувати булевий конструктор

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