Sprawdź poprawność liczb dziesiętnych w JavaScript - IsNumeric ()

2376

Jaki jest najczystszy i najskuteczniejszy sposób sprawdzania poprawności liczb dziesiętnych w JavaScript?

Punkty bonusowe za:

  1. Przejrzystość. Rozwiązanie powinno być czyste i proste.
  2. Międzyplatformowy.

Przypadki testowe:

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
Michael Haren
źródło
256
Tylko nota 99 999 jest poprawną liczbą we Francji, jest ona taka sama jak 99,999 w formacie uk / us, więc jeśli czytasz ciąg znaków, powiedzmy, formularz wejściowy, wtedy 99 99 może być prawdziwe.
Re0sless,
5
Sprawdź także ten post i świetne komentarze .
powtac
79
Przecinek dziesiętny jest standardem w całej Europie i Rosji (z wyjątkiem Wielkiej Brytanii)
Calmarius
90
jQuery 1.7 wprowadził funkcję jQuery.isNumericnarzędzia: api.jquery.com/jQuery.isNumeric
Ates Goral
24
jQuery.isNumericzakończy się niepowodzeniem siódmego przypadku testowego OP ( IsNumeric('0x89f') => *false*). Nie jestem jednak pewien, czy zgadzam się z tym przypadkiem testowym.
Tim Lehner,

Odpowiedzi:

2898

Odpowiedź Joela jest dość bliska, ale nie powiedzie się w następujących przypadkach:

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

Jakiś czas temu musiałem zaimplementować IsNumericfunkcję, aby dowiedzieć się, czy zmienna zawiera wartość liczbową, niezależnie od jej typu , może to być wartość Stringzawierająca wartość liczbową (musiałem rozważyć także notację wykładniczą itp.), NumberObiekt, praktycznie wszystko może być przekazane do tej funkcji, nie mogłem przyjmować żadnych założeń typu, dbając o przymus typu (np. +true == 1;ale truenie należy tego uważać za "numeric").

Myślę, że warto udostępnić ten zestaw testów jednostkowych +30 wykonanych dla wielu implementacji funkcji, a także udostępnić ten, który przejdzie wszystkie moje testy:

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

PS isNaN i isFinite mają mylące zachowanie z powodu wymuszonej konwersji na liczbę. W ES6 Number.isNaN i Number.isFinite rozwiązałyby te problemy. Pamiętaj o tym podczas ich używania.


Aktualizacja : Oto jak robi to teraz jQuery (stabilny w wersji 2.2) :

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

Aktualizacja : Angular 4.3 :

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}
CMS
źródło
26
nie udaje się to w przypadku innych ustawień narodowych, w których używamy przecinków dziesiętnych, ale dodajemy `n = n.replace (/, /,". "); ' przed powrotem, aby to naprawić.
Zoltan Lengyel
5
@RobG, ponieważ takie zachowanie jest celowe, 2e308 > Number.MAX_VALUEponieważ 2e308 == Infinity. Jeśli chcesz funkcji, która zwraca truerównież dodatnie i ujemne wartości nieskończoności, sprawdź funkcję nr 2 w zestawie testów . Twoje zdrowie.
CMS
39
Nawiasem mówiąc, testy jednostkowe są teraz wykorzystywane przez projekt jQuery
CMS
7
jQuery używają teraz również tej implementacji.
RichardTowers,
4
Rozwiązaniem jest tutaj użycie JQuery. Mają teraz jeszcze lepszą implementację tego: github.com/jquery/jquery/blob/master/src/core.js#L230
Robert
337

Arrrgh! Nie słuchaj odpowiedzi na wyrażenia regularne. RegEx jest do tego obrzydliwy i nie mówię tylko o wydajności. Łatwo jest zrobić subtelne, niemożliwe do wykrycia błędy za pomocą wyrażenia regularnego.

Jeśli nie możesz użyć isNaN(), powinno to działać znacznie lepiej:

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

Oto jak to działa:

(input - 0)Wyrażenie zmusza JavaScript robić typu przymus na wartość wejściowa; należy go najpierw interpretować jako liczbę dla operacji odejmowania. Jeśli konwersja na liczbę nie powiedzie się, wyrażenie zakończy się wynikiem NaN. Ten wynik liczbowy jest następnie porównywany z oryginalną wartością, którą podałeś. Ponieważ lewa strona jest teraz numeryczna, ponownie stosuje się wymuszenie typu. Teraz, gdy dane wejściowe z obu stron zostały wymuszone na ten sam typ z tej samej pierwotnej wartości, można by pomyśleć, że powinny zawsze być takie same (zawsze prawdziwe). Istnieje jednak specjalna reguła, która mówi, że NaNnigdy nie jest równa NaN, a więc wartość, której nie można przekonwertować na liczbę (i tylko wartości, których nie można przekonwertować na liczby), spowoduje fałsz.

Kontrola długości dotyczy specjalnego przypadku z pustymi łańcuchami. Zauważ też, że spada on w teście 0x89f, ale to dlatego, że w wielu środowiskach jest to dobry sposób na zdefiniowanie literału liczbowego. Jeśli chcesz uchwycić ten konkretny scenariusz, możesz dodać dodatkową kontrolę. Co więcej, jeśli to jest powód, dla którego nie używasz, isNaN()po prostu obejmij własną funkcję, isNaN()która może również wykonać dodatkowe sprawdzenie.

Podsumowując, jeśli chcesz wiedzieć, czy wartość można przekonwertować na liczbę, faktycznie spróbuj przekonwertować ją na liczbę.


Wróciłem i zbadałem, dlaczego łańcuch białych znaków nie ma oczekiwanego wyniku i myślę, że teraz go rozumiem: 0zamiast tego jest wymuszany pusty ciąg NaN. Po prostu przycięcie sznurka przed sprawdzeniem długości poradzi sobie z tym przypadkiem.

Uruchamianie testów jednostkowych dla nowego kodu i kończy się niepowodzeniem tylko w przypadku literałów nieskończoności i logicznej, a jedynym problemem, który powinien stanowić problem, jest wygenerowanie kodu (naprawdę, kto napisałby literał i sprawdził, czy jest to wartość liczbowa? Powinieneś wiedzieć ), a byłby to jakiś dziwny kod do wygenerowania.

Ale znowu jedynym powodem, aby tego użyć, jest to, że z jakiegoś powodu musisz unikać toNaN ().

Joel Coehoorn
źródło
28
To nie działa na ciągi białych, na przykład IsNumeric(' '), IsNumeric('\n\t')itd wszystkim powróttrue
Crescent Fresh
29
Nie powiedzie się również na Numberliterach IsNumeric(5) == false;sprawdź zestaw testów jednostkowych, które opublikowałem, ta funkcja jest liczbą 16w zestawie testów. stackoverflow.com/questions/18082/...
CMS
20
Nie mogę uwierzyć, że nikt nie zwrócił uwagi na użycie wyrażenia regularnego (zamień) po ostrzeżeniu o nieużywaniu wyrażeń regularnych ... To prawda, że ​​zamiana białych znaków jest prostsza niż parsowanie liczb, ale jest zdecydowanie „niepewna”.
Patrick M,
1
@Oriol To duży problem ... bez poprawek bezpieczeństwa wydanych po tej dacie, oderwanie się od XP powinno być priorytetem.
Joel Coehoorn,
1
@Oriol XP lub nie, jeśli używasz IE8 lub starszej wersji, używasz strasznie nieaktualnego oprogramowania. Udzielony XP nie może uruchomić IE9 +, więc użyj Chrome lub FF. Ludzie żyjący w przeszłości za pomocą IE8 są zmorą istnienia wielu twórców stron internetowych. Gdybym mógł cofnąć czas, który poświęciłem na upewnienie się, że doskonale działający kod działa również w IE8 ... Dla mnie pobranie kodu działającego w FF i Chrome i załatanie go w IE8 jest tak samo praktyczne, jak wykonanie programu Windows 8 i upewniając się, że działa tak samo w systemie Windows 3.1.
chiliNUT
70

Ten sposób wydaje się działać dobrze:

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

W jednej linii:

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

I aby to przetestować:

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

Pożyczyłem to wyrażenie regularne z http://www.codetoad.com/javascript/isnumeric.asp . Wyjaśnienie:

/^ 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
Michael Haren
źródło
1
// NALEŻY DODAWAĆ RÓWNIEŻ DO TESTU wyniki + = (! IsNumeric ('-')? "Pass": "Fail") + ": IsNumeric ('-') => false \ n"; wyniki + = (! IsNumeric ('01 ')? "Pass": "Fail") + ": IsNumeric ('01') => false \ n"; wyniki + = (! IsNumeric ('- 01')? "Pass": "Fail") + ": IsNumeric ('- 01') => false \ n"; wyniki + = (! IsNumeric ('000')? "Pass": "Fail") + ": IsNumeric ('000') => false \ n";
Dan
co to robi? / ^ - {0,1} \ d * \. {0,1} \ d + $ /
call-me
można zastąpić „{0,1}” słowem „?”, więc wyrażenie regularne będzie wyglądać tak: /^-?\d*\.?\d+$/?
Chmura,
ładny i prosty.
łamacz
53

Wieśniak! Interfejs użytkownika używa tego:

isNumber: function(o) {
    return typeof o === 'number' && isFinite(o);
}
rumianek
źródło
25
To jest bardziej sprawdzanie typu zmiennej w przeciwieństwie do zawartości liczby. Nie powiedzie się również w przypadku liczb utworzonych za pomocą new Number(1).
alex
4
Jak mówi Alex, to tak naprawdę nie odpowiada na postawione pytanie, ponieważ to się nie powiedzie, jeśli o = "1001".
Sprawa
50
function IsNumeric(num) {
     return (num >=0 || num < 0);
}

Działa to również dla liczb typu 0x23.

użytkownik189277
źródło
29
IsNumeric(''), IsNumeric(' '), IsNumeric(true), IsNumeric(false), IsNumeric(null)Powrót truezamiast false.
Oriol
49

Przyjęta odpowiedź nie zdała testu nr 7 i myślę, że to dlatego, że zmieniłeś zdanie. Jest to więc odpowiedź na zaakceptowaną odpowiedź, z którą miałem problemy.

Podczas niektórych projektów musiałem zweryfikować niektóre dane i mieć jak największą pewność, że jest to wartość liczbowa javascript, której można używać w operacjach matematycznych.

jQuery i niektóre inne biblioteki javascript zawierają już taką funkcję, zwykle wywoływaną isNumeric. Istnieje również post dotyczący przepełnienia stosu , który został powszechnie zaakceptowany jako odpowiedź, ta sama ogólna procedura, której używają wspomniane biblioteki.

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

Po pierwsze, powyższy kod zwróciłby wartość true, jeśli argument byłby tablicą o długości 1, a ten pojedynczy element był typu uznanego za numeryczny przez powyższą logikę. Moim zdaniem, jeśli jest to tablica, to nie jest liczbowa.

Aby złagodzić ten problem, dodałem czek, aby zdyskontować tablice z logiki

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

Oczywiście możesz zamiast tego użyć Array.isArray, jquery $.isArraylub prototypuObject.isArrayObject.prototype.toString.call(n) !== '[object Array]'

Mój drugi problem polegał na tym, że ciągi liczb całkowitych ujemnych liczb szesnastkowych („-0xA” -> -10) nie były liczone jako liczby. Jednak dodatnie szesnastkowe ciągi literału liczby całkowitej („0xA” -> 10) były traktowane jako liczby. Musiałem być poprawnym numerycznie.

Następnie zmodyfikowałem logikę, aby uwzględnić to.

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

Jeśli martwisz się tworzeniem wyrażenia regularnego za każdym razem, gdy wywoływana jest funkcja, możesz przepisać ją w ramach zamknięcia, coś takiego

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

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

Następnie wziąłem CMS +30 przypadków testowych i sklonowałem testy na jsfiddle, dodałem moje dodatkowe przypadki testowe i moje wyżej opisane rozwiązanie.

Może nie zastąpić powszechnie przyjętej / używanej odpowiedzi, ale jeśli jest to więcej, niż oczekujesz, jako wynik funkcji isNumeric, to mam nadzieję, że będzie to pomocne.

EDYCJA: Jak zauważył Bergi , istnieją inne możliwe obiekty, które można by uznać za numeryczne i lepiej byłoby umieścić na białej liście niż na czarnej liście. Mając to na uwadze, dodałbym do kryteriów.

Chcę, aby moja funkcja isNumeric uwzględniała tylko liczby lub ciągi znaków

Mając to na uwadze, lepiej byłoby użyć

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(/^-/, ''));
}

Przetestuj rozwiązania

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>

Xotic750
źródło
2
Jest to moim zdaniem najbardziej ekranowana funkcja; ostatni. Przyjęta odpowiedź obejmuje prawdopodobnie 99,99% wszystkich przypadków, ale ta ma prawdopodobnie 100% a) przypadków z niewielkim narzutem.
Samuel
Zapomniałeś o dosłownym punkcie „99,999” Foating-Point. Jest to ważny numer w całej Europie z wyjątkiem Wielkiej Brytanii
Andrii Horda
Nie zapomniano, nie było to coś, co uważałem za numeryczne w znaczeniu liczb Javascript, OP stwierdził równieżIsNumeric('99,999') => false
Xotic750
34

Tak, wbudowany isNaN(object)będzie znacznie szybszy niż jakakolwiek analiza wyrażeń regularnych, ponieważ jest wbudowany i skompilowany, a nie interpretowany w locie.

Chociaż wyniki różnią się nieco od tego, czego szukasz ( spróbuj ):

                                              // 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
travis
źródło
18

Użyj funkcji isNaN. Wierzę, że jeśli przetestujesz !isNaN(yourstringhere)to działa dobrze w każdej z tych sytuacji.

bubbassauro
źródło
Uwaga
:! IsNaN
if (! (x == null || isNaN (x))) alert („isNumeric”); // Ale to rozwiązanie akceptuje 0x40, więc nadal nie jest to, czego chciał operacja.
jakieś
Zauważ, że isNaN („Infinity”) === false, co prawdopodobnie również nie jest tym, czego chcesz (ale także nie zdarzy się w prawdziwym życiu).
Erik Hesselink
16

Od jQuery 1.7 możesz używać 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

Pamiętaj tylko, że w przeciwieństwie do tego, co powiedziałeś, 0x89fjest to poprawna liczba (hexa)

Kuf
źródło
OP chce prawidłowej liczby dziesiętnej , więc jQuery isNumeric nie pasuje. Nie działa również w przypadku bardzo dużych liczb.
RobG
13

Można to zrobić bez RegExp as

function IsNumeric(data){
    return parseFloat(data)==data;
}
Wodny
źródło
5
Jeśli używamy ==, zwróci prawdę nawet dla liczb prezentowanych jako ciągi znaków. Tak więc „42” będzie liczone jako poprawna liczba w przypadku „==” i będzie liczone jako nieprawidłowe w przypadku ===
Aquatic
zwraca wartość true dla „-0.”, „-.0”, „.0” i „0.”
Janus Troelsen
8
return (input - 0) == input && input.length > 0;

nie działało dla mnie. Kiedy wprowadziłem alert i przetestowałem, input.lengthbyło undefined. Myślę, że nie ma właściwości do sprawdzania długości całkowitej. Więc to, co zrobiłem, było

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

Działa dobrze.

jayakumar
źródło
7

Jeśli się nie mylę, powinno to być zgodne z dowolną poprawną wartością numeru JavaScript, z wyłączeniem stałych ( Infinity, NaN) i operatorów znaków +/ -(ponieważ, o ile mnie to nie dotyczy, są oddzielnymi operatorami):

Potrzebowałem tego dla tokenizera, w którym wysłanie numeru do JavaScript w celu oceny nie było opcją ... To zdecydowanie nie jest najkrótsze możliwe wyrażenie regularne, ale uważam, że przechwytuje wszystkie subtelności składni liczb 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

Prawidłowe liczby obejmują:

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

Nieprawidłowe liczby to

 - 00e1
 - 01e1
 - 00.0
 - 00x0
 - .
 - .e0
Jonathan Spooner
źródło
7

Jedyny problem miałem z @ CMS za odpowiedź jest wyłączenie NaNi nieskończoności, które są przydatne numery dla wielu sytuacjach. Jednym ze sposobów, aby sprawdzić, czy NaNjest to do sprawdzenia wartości liczbowych, które NIE równa sami NaN != NaN! Tak naprawdę są 3 testy, z którymi chciałbyś się uporać ...

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

Mój isComparableNumber jest dość zbliżony do innej eleganckiej odpowiedzi , ale obsługuje szesnastkowe i inne ciągi znaków liczb.

płyty
źródło
6

Dla mnie to najlepszy sposób:

isNumber : function(v){
   return typeof v === 'number' && isFinite(v);
}
InsertNameHere
źródło
Niestety jest to
swego rodzaju STRICT
6

Chciałbym dodać następujące:

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

Dodatnie liczby szesnastkowe zaczynają się od, 0xa ujemne liczby szesnastkowe zaczynają się od -0x. Dodatnie liczby ósemkowe zaczynają się od, 0a ujemne liczby ósemkowe zaczynają się od -0. Ten bierze pod uwagę większość tego, co już wspomniano, ale zawiera liczby szesnastkowe i ósemkowe, ujemny naukowy, Nieskończoność i usunął dziesiętny naukowy ( 4e3.2jest nieważny).

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));
}
Marius
źródło
6

Myślę, że funkcja parseFloat może tutaj wykonać całą pracę. Poniższa funkcja przechodzi wszystkie testy na tej stronie, w tym isNumeric(Infinity) == true:

function isNumeric(n) {

    return parseFloat(n) == n;
}
John Mikic
źródło
Tak, doszedłem również do tego wniosku. Podoba mi się również sposób, w jaki tablice są traktowane przy użyciu tej metody; tablica z jedną wartością liczy się jako ta wartość, ale wszystko inne zawiedzie: IsNumeric([3]) == true; IsNumeric([]) == false; IsNumeric([3, 4]) == false; Ale wyobrażam sobie, że to kwestia gustu!
Mark Birbeck
4

Kilka testów do dodania:

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

Wymyśliłem to:

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

Rozwiązanie obejmuje:

  • Opcjonalny znak ujemny na początku
  • Pojedyncza zero lub jedna lub więcej cyfr, które nie zaczynają się od 0, lub nic, jeśli następuje kropka
  • Kropka, po której następuje 1 lub więcej liczb
mięso doniczkowe
źródło
4

Wartość całkowitą można zweryfikować przez:

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

W ten sposób jest łatwiej i szybciej! Wszystkie testy są sprawdzane!

solidarius
źródło
4

Oto nieco ulepszona wersja (prawdopodobnie najszybsza droga), której używam zamiast dokładnego wariantu jQuery, naprawdę nie wiem, dlaczego tego nie używają:

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

Wadą wersji jQuery jest to, że jeśli przejdą ciąg z wiodącym numeryczne i końcowe litery jak będzie wyodrębnić część numeryczną i odesłać 123, ale drugi strażnik będzie to nie tak. Dzięki jednemu operatorowi umrze na pierwszym straży, ponieważ + rzuca NaN dla takich hybryd :) Trochę wydajności, ale myślę, że jest to znaczny zysk semantyczny."123abc"parseFloat | parseIntisFinite+

Arman McHitarian
źródło
2
Uwaga, jednoargumentowe „+” wywoła wartość objectOf () na obiekcie - zobacz to jsfiddle . Również to nie odnosi się do wiodących białych znaków, podobnie jak wiodąca odpowiedź.
kamera douszna
3

Moje rozwiązanie

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

Wygląda na to, że działa w każdej sytuacji, ale mogę się mylić.

Manusoftar
źródło
Ten regex byłby mniej mylący, gdybyś niepotrzebnie nie unikał znaków, używał ?dla {0,1}i \ddla [0-9]. Ponadto, +a następnie owijając go (?:){0,1}, możesz równie dobrze wykorzystać *i zapomnieć o grupach (nie) przechwytujących.
alex,
3

Używam prostszego rozwiązania:

function isNumber(num) {
    return parseFloat(num).toString() == num
}
Ali Gonabadi
źródło
5
to nie powiedzie się na końcu ze zbędnymi zerami. przykład: „10,0”
Janus Troelsen
3

To powinno działać. Niektóre przedstawione tu funkcje są wadliwe, powinny też być szybsze niż jakakolwiek inna funkcja tutaj.

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

Wyjaśnione:

Utwórz kopię samego siebie, a następnie konwertuje liczbę na liczbę zmiennoprzecinkową, a następnie porównuje się z liczbą oryginalną, jeśli nadal jest liczbą (całkowitą lub zmiennoprzecinkową) i pasuje do pierwotnej liczby, co oznacza, że ​​rzeczywiście jest liczbą.

Działa zarówno z ciągami liczbowymi, jak i liczbami zwykłymi. Nie działa z liczbami szesnastkowymi.

Ostrzeżenie: używaj na własne ryzyko, bez gwarancji.

532188
źródło
4
używaj na własne ryzyko, bez gwarancji nie użyłbym kodu, do którego autor nie jest pewien;)
alex
1
@Alex, Przynajmniej masz własne zdanie na temat rzeczy. Nie krytykuj cały czas.
Stewart Mbofana
3

Żadna z odpowiedzi nie zwraca falsepustych ciągów, to poprawka ...

function is_numeric(n)
{
 return (n != '' && !isNaN(parseFloat(n)) && isFinite(n));
}
John
źródło
3

Aby sprawdzić, czy zmienna zawiera prawidłową liczbę, a nie tylko ciąg znaków, który wygląda jak liczba, Number.isFinite(value)Można .

Od tego czasu jest to część języka ES2015

Przykłady:

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
adius
źródło
1
Sądzę, że wiele osób odwołuje się do tego pytania w celu analizowania danych wejściowych użytkownika, które zwykle są ciągiem znaków . Ta odpowiedź nie udaje się w tych przypadkach, jak poprawnie podajesz w przykładach, np.Number.isFinite('0') -> false
Michael Haren,
Masz całkowitą rację. Starałem się, żeby to było jasne.
adius
3
function inNumeric(n){
   return Number(n).toString() === n;
}

Jeśli n jest liczbowe Number(n), zwróci wartość liczbową i toString()zwróci ją z powrotem do łańcucha. Ale jeśli n nie jest liczbą, Number(n)to zwróci, NaNwięc nie będzie pasować do oryginałun

chrmcpn
źródło
Ten fragment kodu może rozwiązać pytanie, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu. Staraj się również nie tłoczyć kodu objaśniającymi komentarzami, ponieważ zmniejsza to czytelność zarówno kodu, jak i objaśnień!
Do widzenia StackExchange
2

Zdaję sobie sprawę, że na to pytanie udzielono odpowiedzi wiele razy, ale poniżej znajduje się porządny kandydat, który może być przydatny w niektórych scenariuszach.

należy zauważyć, że zakłada, że ​​„.42” NIE jest liczbą, a „4.” NIE jest liczbą, więc należy to wziąć pod uwagę.

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

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

isDecimalPrzechodzi następujący test:

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

Chodzi o to, że każda liczba lub liczba całkowita ma jedną „kanoniczną” reprezentację ciągu, a każda niekanoniczna reprezentacja powinna zostać odrzucona. Rzucamy więc na liczbę i wstecz i sprawdzamy, czy wynikiem jest oryginalny ciąg.

To, czy te funkcje są dla Ciebie przydatne, zależy od przypadku użycia. Jedną z cech jest to, że różne ciągi reprezentują różne liczby (jeśli oba przekazują znakisNumber() test).

Dotyczy to np. Liczb jako nazw właściwości obiektów.

var obj = {};
obj['4'] = 'canonical 4';
obj['04'] = 'alias of 4';
obj[4];  // prints 'canonical 4' to the console.
donquixote
źródło
2

knockoutJs Wbuduj funkcje sprawdzania poprawności biblioteki

Po rozszerzeniu pole jest sprawdzane

1) numer

self.number = ko.observable(numberValue).extend ({number: true}) ;

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

self.number = ko.observable(numberValue).extend ({cyfra: prawda}) ;

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) min. I maks

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

To pole przyjmuje wartość tylko od 5 do 10

TestCase

numberValue = '5'    --> true
numberValue = '6'    --> true
numberValue = '6.5'  --> true
numberValue = '9'    --> true
numberValue = '11'   --> false
numberValue = '0'    --> false
numberValue = ''    --> false
nav0611
źródło
2

Jeśli chcesz sprawdzić poprawność specjalnego zestawu miejsc po przecinku, możesz użyć tego prostego 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;
}
studio-klik
źródło
2

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

Nic bardzo innego, ale możemy użyć konstruktora boolowskiego

Shishir Arora
źródło