Überprüfen Sie, ob eine Zeichenfolge eine positive Ganzzahl ist

201

Ich möchte, dass der einfachste ausfallsichere Test überprüft, ob eine Zeichenfolge in JavaScript eine positive Ganzzahl ist.

isNaN(str)Gibt true für alle Arten von Nicht-Integer-Werten zurück und parseInt(str)gibt Integer für Float-Strings wie "2.5" zurück. Und ich möchte auch kein jQuery-Plugin verwenden müssen.

Mick Byrne
quelle
7
Erlaubst du "+2"? Wie wäre es mit "0.1e1"? Wie wäre es mit "1.0000"?
Phrogz
Die isNaN()Funktion verhält sich so, wie sie es tut, da das Konzept Not a Numberin der Gleitkommaspezifikation nach IEEE 794 eine sehr spezifische Bedeutung hat. Es ist nicht beabsichtigt, eine Antwort auf die einfache umgangssprachliche Frage zu geben: "Ist dieser Wert keine Zahl?"
Pointy
3
Die Frage ist extrem vage. Sie können nicht überprüfen, ob "eine Zeichenfolge eine Ganzzahl ist", da es so etwas nicht gibt - kein Objekt kann gleichzeitig eine Zeichenfolge und eine Zahl sein. Sie meinten wahrscheinlich "wie man testet, ob eine Zeichenfolge eine gültige Darstellung einer ganzen Zahl ist", aber um dies zu beantworten, müssen wir wissen, über welche Sprache oder "Kultur" Sie sprechen. Zum Beispiel ٢‎٣٤oder MCMXIXsind beide gültige Ganzzahldarstellungen, aber ich glaube nicht, dass Sie nach einem Code suchen, der diese analysieren kann. Könnten Sie angeben, welche Zahlenformate Sie unterstützen möchten, da die Leute darüber verwirrt zu sein scheinen?
Georg
5
Ich denke, "vage bis zum Äußersten" ist selbst ein bisschen extrem; aber trotzdem ... Der Kontext ist die Validierung eines Mengeneingabefelds in einem Einkaufswagen, der in einem englischsprachigen Land verwendet wird, also nur westliche Ziffern. Mit "positiv" meinte ich größer als Null. Würde ich Folgendes akzeptieren: "+2" ja, "0.1e1" nein, "1.000" sicher warum nicht. Wenn Sie jedoch eine Antwort geben können, die angepasst werden kann, um diese verschiedenen speziellen Szenarien einzuschließen / auszuschließen, verspreche ich Ihnen zusätzliche Verbesserungen (und ich bin sicher, dass dies auch andere tun werden).
Mick Byrne

Antworten:

296

Zwei Antworten für Sie:

  • Basierend auf dem Parsen

  • Regulären Ausdruck

Beachten Sie, dass ich in beiden Fällen "positive Ganzzahl" als eingeschlossen interpretiert habe 0, obwohl dies 0nicht positiv ist. Ich füge Notizen hinzu, wenn Sie nicht zulassen möchten 0.

Basierend auf Parsing

Wenn Sie möchten, dass es sich um eine normalisierte dezimale Ganzzahlzeichenfolge über einen angemessenen Wertebereich handelt, können Sie Folgendes tun:

function isNormalInteger(str) {
    var n = Math.floor(Number(str));
    return n !== Infinity && String(n) === str && n >= 0;
}

oder wenn Sie Leerzeichen und führende Nullen zulassen möchten:

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

Live-Testbed (ohne Behandlung von führenden Nullen oder Leerzeichen):

Live-Testbed ( mit Behandlung für führende Nullen und Leerzeichen):

Wenn Sie nicht zulassen möchten 0, wechseln Sie einfach >= 0zu > 0. (Oder entfernen Sie in der Version, die führende Nullen zulässt, die || "0"in der replaceZeile.)

Wie das funktioniert:

  1. In der Version, die Leerzeichen und führende Nullen zulässt:

    • str = str.trim(); Entfernt alle führenden und nachfolgenden Leerzeichen.
    • if (!str) fängt eine leere Zeichenfolge ab und kehrt zurück, was keinen Sinn macht, den Rest der Arbeit zu erledigen.
    • str = str.replace(/^0+/, "") || "0"; Entfernt alle führenden Nullen aus der Zeichenfolge. Wenn dies jedoch zu einer leeren Zeichenfolge führt, wird eine einzelne 0 wiederhergestellt.
  2. Number(str): In streine Zahl konvertieren ; Die Zahl kann durchaus einen Bruchteil haben oder sein NaN.

  3. Math.floor: Schneiden Sie die Zahl ab (hackt einen Bruchteil ab).

  4. String(...): Konvertiert das Ergebnis zurück in eine normale Dezimalzeichenfolge. Für wirklich große Zahlen wird dies in die wissenschaftliche Notation gehen, was diesen Ansatz brechen kann. (Ich weiß nicht genau, wo die Aufteilung ist, die Details sind in der Spezifikation enthalten , aber für ganze Zahlen glaube ich, dass es an dem Punkt ist, an dem Sie 21 Stellen überschritten haben [zu diesem Zeitpunkt ist die Zahl sehr ungenau geworden, wie IEEE-754 Zahlen mit doppelter Genauigkeit haben nur ungefähr 15 Stellen Genauigkeit.)

  5. ... === str: Vergleicht das mit der ursprünglichen Zeichenfolge.

  6. n >= 0: Überprüfen Sie, ob es positiv ist.

Beachten Sie, dass dies für die Eingabe fehlschlägt, für "+1"jede Eingabe in wissenschaftlicher Notation, die zu diesem String(...)Zeitpunkt nicht wieder in dieselbe wissenschaftliche Notation umgewandelt wird , und für jeden Wert, den die Art der von JavaScript verwendeten Zahl verwendet (binärer Gleitkomma mit doppelter Genauigkeit nach IEEE-754). kann nicht genau darstellen, welche Analyse näher an einem anderen Wert als dem angegebenen liegt (der viele ganze Zahlen über 9.007.199.254.740.992 enthält; zum Beispiel 1234567890123456789wird fehlschlagen). Ersteres ist eine einfache Lösung, die beiden letzteren nicht so sehr.

Regulären Ausdruck

Der andere Ansatz besteht darin, die Zeichen der Zeichenfolge über einen regulären Ausdruck zu testen, wenn Ihr Ziel darin besteht, nur eine Option +gefolgt von einer 0oder einer Zeichenfolge im normalen Dezimalformat zuzulassen (z. B.) :

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

Live-Testumgebung:

Wie das funktioniert:

  1. ^: Match Anfang der Zeichenfolge

  2. \+?: Erlaube eine einzelne, optionale +(entferne diese, wenn du nicht willst)

  3. (?:...|...): Erlauben Sie eine dieser beiden Optionen (ohne eine Erfassungsgruppe zu erstellen):

    1. (0|...): Allein zulassen 0...

    2. (...|[1-9]\d*): ... oder eine Zahl, die mit etwas anderem als 0und gefolgt von einer beliebigen Anzahl von Dezimalstellen beginnt .

  4. $: Match Ende der Zeichenfolge.

Wenn Sie nicht zulassen möchten 0(weil es nicht positiv ist), wird der reguläre Ausdruck gerecht /^\+?[1-9]\d*$/(z. B. können wir die Abwechslung verlieren, die wir zulassen mussten 0).

Wenn Sie führende Nullen (0123, 00524) zulassen möchten, ersetzen Sie einfach den Wechsel (?:0|[1-9]\d*)durch\d+

function isNormalInteger(str) {
    return /^\+?\d+$/.test(str);
}

Wenn Sie Leerzeichen zulassen möchten, fügen Sie diese \s*direkt nach ^und \s*kurz vor hinzu $.

Hinweis für die Umrechnung in eine Zahl: Bei modernen Motoren wäre es wahrscheinlich in Ordnung, sie zu verwenden +stroder Number(str)zu tun, aber ältere Motoren erweitern diese möglicherweise auf eine nicht standardmäßige (aber früher zulässige) Weise, die besagt, dass eine führende Null Oktal bedeutet (Basis 8), z. B. "010" => 8. Sobald Sie die Zahl validiert haben, können Sie sicher parseInt(str, 10)sicherstellen, dass sie als Dezimalzahl analysiert wird (Basis 10). parseIntwürde den Müll am Ende des Strings ignorieren, aber wir haben sichergestellt, dass es keinen mit dem regulären Ausdruck gibt.

TJ Crowder
quelle
beide Number(' ')und Number('')return 0while sollten NaNstattdessen zurückkehren.
Neurino
@TJCrowder ok, aber ich brauche Strings wie '' 2a '', um irgendwie abgelehnt zu werden, parseIntkehrt zurück 2.
Neurino
@neurino: /\D/.test('2a')ist wahr (weil es eine nicht-Ziffer gibt). Also vielleicht if (!/\D/.test(str) && !isNan((num = parseInt(str, 10))) { /* Valid number in num */}... ganz oben auf meinem Kopf ...
TJ Crowder
In Bezug auf die Leistung, welche Methode wäre schneller? Oder welches ist ratsam?
Phkavitha
@phkavitha: Die Antwort auf Fragen zur JavaScript-Leistung lautet fast immer "Es kommt darauf an", weil die verschiedenen Engines so unterschiedlich sind. Sie können Ihre Ziel-Engines / Browser mit jsperf.com testen . Ich würde nicht denken, dass diese Operation wahrscheinlich der Engpass in einer bestimmten App sein würde ... :-)
TJ Crowder
76

Lösung 1

Wenn wir betrachten eine JavaScript - Integer - Wert von maximal zu sein 4294967295(dh Math.pow(2,32)-1), dann wird die folgende kurze Lösung wird perfekt funktionieren:

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

BESCHREIBUNG:

  1. Der Zero-Fill-Rechtsschieber macht drei wichtige Dinge:
    • schneidet den Dezimalteil ab
      • 123.45 >>> 0 === 123
    • macht die Verschiebung für negative Zahlen
      • -1 >>> 0 === 4294967295
    • "funktioniert" im Bereich von MAX_INT
      • 1e10 >>> 0 === 1410065408
      • 1e7 >>> 0 === 10000000
  2. parseFloatkorrigiert das Parsen von Zeichenfolgenummern (Einstellung NaNfür nicht numerische Zeichenfolgen)

TESTS:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e7"                  : false
"1e7"                   : true
"1e10"                  : false
"1edf"                  : false
" "                     : false
""                      : false

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


Lösung 2

Ein anderer Weg ist gut für alle numerischen Werte, die bis Number.MAX_VALUEzu ungefähr gültig sind , dh bis ungefähr 1.7976931348623157e+308:

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

BESCHREIBUNG:

  1. !isNaN(parseFloat(n))verwendet wird , filtern reine Stringwerte, beispielsweise "", " ", "string";
  2. 0 <= ~~nFilter negativ und groß nicht ganzzahlige Werte, zum Beispiel "-40.1", "129000098131766699";
  3. (!isNaN(parseFloat(n)) && 0 <= ~~n)Gibt zurück, truewenn der Wert sowohl numerisch als auch positiv ist .
  4. 0 === n % (...)prüft, ob der Wert nicht float ist - hier (...)(siehe 3) wird wie 0im Fall von falseund wie 1im Fall von ausgewertet true.

TESTS:

"0"                     : true
"23"                    : true
"-10"                   : false
"10.30"                 : false
"-40.1"                 : false
"string"                : false
"1234567890"            : true
"129000098131766699.1"  : false
"-1e10"                 : false
"1e10"                  : true
"1edf"                  : false
" "                     : false
""                      : false

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


Die vorherige Version:

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

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

Vision
quelle
Versuchen Sie eine leere Zeichenfolge oder eine große Zahl wie 1290000981231123.1 - jsfiddle.net/5UCy4/1
Niko
@gdoron Das gleiche wie ~~val, Bruchteil abschneiden. Es ist etwas schneller, da eine bitweise Operation anstelle von zwei ausgeführt wird.
VisioN
Gute Antwort. Persönlich würde ich es vorziehen, aus Gründen der Lesbarkeit etwas ausführlicher zu sein(!isNaN(parseFloat(n)) && n % 1 === 0 && 0 <= ~~n)
Ramy Nasr
true, false, 0xFFund andere Werte schaffen es, isPositiveIntegerohne erkannt zu werden.
Xeoncross
1
Dieser behandelt sogar gepolsterte Nullen (gut!). Sie können das zu Ihren Tests hinzufügen.
Rashack
21

Es sieht so aus, als wäre ein regulärer Ausdruck der richtige Weg:

var isInt = /^\+?\d+$/.test('the string');
Niko
quelle
Schließen, es sei denn, "1.0" oder ".1e1" sind zulässig.
Phrogz
Nun, 1290000192379182379123782900192981231 ist eine Ganzzahl, die jedoch nicht genau in nativen JavaScript-Zahlen dargestellt werden kann. Daher ist es bei einem regulären Ausdruck weiterhin erforderlich, eine numerische Konvertierung durchzuführen und zu überprüfen, ob sie funktioniert.
Pointy
Dies ist eine sehr ungenaue Lösung.
usr
@usr: Ich nehme an, es erlaubt zu führen, 0wo man normalerweise nicht erwartet, aber zum größten Teil scheint es in Ordnung zu sein.
TJ Crowder
Der Bereich wird nicht auf höchstens 2 ^ 31-1 überprüft, und es werden keine arabischen Ziffern zugelassen. Dies ist ein Hack, keine gute Lösung. Die beste Lösung hat die meisten positiven Stimmen in dieser Frage. Warum nicht diesen benutzen? Es ist in jeder Hinsicht besser.
usr
17

Die moderne Lösung, die im Knoten und in über 90% aller Browser (außer IE und Opera Mini) funktioniert, besteht darin, Number.isInteger zu verwenden, gefolgt von einer einfachen positiven Prüfung.

Number.isInteger(x) && x > 0

Dies wurde in ECMAScript 2015 abgeschlossen .

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

Das Polyfil ist:

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

Wenn Sie Eingaben unterstützen müssen, die möglicherweise in Zeichenfolgen- oder Zahlenform vorliegen, können Sie diese Funktion verwenden. Ich habe eine große Testsuite gegen geschrieben, nachdem alle vorhandenen Antworten (2/1/2018) bei einer Eingabe fehlgeschlagen sind.

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

Dies ist fast eine doppelte Frage für diese:

Überprüfen Sie Dezimalzahlen in JavaScript - IsNumeric ()

Die Antwort lautet:

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

Eine positive ganze Zahl wäre also:

function isPositiveInteger(n) {
  var floatN = parseFloat(n);
  return !isNaN(floatN) && isFinite(n) && floatN > 0
      && floatN % 1 == 0;
}
Chango
quelle
Ich weiß, dass es fast ein Duplikat zu dieser Frage zum Überprüfen von Zahlen in JavaScript ist. Ich habe das Ganze durchgelesen, aber ich dachte, eine Frage speziell zu Zeichenfolgendarstellungen von Ganzzahlen hätte eine eigene Seite verdient.
Mick Byrne
2
return ((parseInt(str, 10).toString() == str) && str.indexOf('-') === -1);

funktioniert nicht, wenn Sie einen String wie '0001' angeben

Sebas
quelle
2

Meine Funktion prüft, ob die Zahl + ve ist und auch einen Dezimalwert haben kann.

       function validateNumeric(numValue){
            var value = parseFloat(numValue);
            if (!numValue.toString().match(/^[-]?\d*\.?\d*$/)) 
                    return false;
            else if (numValue < 0) {
                return false;
            }
            return true;        
        }
Deepak Nirala
quelle
2

Um auf der obigen Antwort von VisioN aufzubauen, können Sie Folgendes verwenden, wenn Sie das jQuery-Validierungs-Plugin verwenden:

$(document).ready(function() {
    $.validator.addMethod('integer', function(value, element, param) {
        return (value >>> 0 === parseFloat(value) && value > 0);
    }, 'Please enter a non zero integer value!');
}

Dann können Sie in Ihrem normalen Regelsatz Folgendes verwenden oder dynamisch hinzufügen:

$("#positiveIntegerField").rules("add", {required:true, integer:true});
usr-bin-trinken
quelle
2

Einfach

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

console.log(isInteger(1));

Sie können Number auch erweitern und die Funktion über den Prototyp zuweisen.

manish kumar
quelle
1

Wenn Sie HTML5-Formulare verwenden, können Sie das Attribut min="0"für das Formularelement verwenden <input type="number" />. Dies wird von allen gängigen Browsern unterstützt. Es beinhaltet kein Javascript für solch einfache Aufgaben, sondern ist in den neuen HTML-Standard integriert. Es ist unter https://www.w3schools.com/tags/att_input_min.asp dokumentiert

mggluscevic
quelle
0

(~~a == a)Wo aist die Zeichenfolge?

Gus
quelle
1
Dies schlägt bei negativen Zahlen fehl: ~~"-1" == "-1"wird zurückgegeben true. Und OP bat nur um positive ganze Zahlen.
Igor Milla
1
Scheitert auch für '' und ''.
Neverfox