webentwicklung-frage-antwort-db.com.de

Regex entspricht genau 5 Zahlen und einem optionalen Leerzeichen

Ich musste vor kurzem einen regulären Ausdruck erstellen, um die Eingabe in JavaScript zu überprüfen. Die Eingabe konnte 5 oder 6 Zeichen lang sein und musste genau 5 Zahlen und ein optionales Leerzeichen enthalten, das an einer beliebigen Stelle in der Zeichenfolge stehen konnte. Ich bin überhaupt nicht an Regex-Klugheit interessiert und obwohl ich versucht habe, nach einem besseren Weg zu suchen, endete ich damit: 

(^\d{5}$)|(^ \d{5}$)|(^\d{5} $)|(^\d{1} \d{4}$)|(^\d{2} \d{3}$)|(^\d{3} \d{2}$)|(^\d{4} \d{1}$)  

Das macht was ich brauche, also sind die erlaubten Eingaben (wenn 0 irgendeine Zahl ist) 

'00000'  
' 00000'  
'0 0000'  
'00 000'  
'000 00'  
'0000 0'  
'00000 '

Ich bezweifle, dass dies der einzige Weg ist, eine solche Anpassung mit Regex zu erreichen, aber ich habe keinen Weg gefunden, dies sauberer zu machen. Meine Frage ist also, wie kann man das besser schreiben?

Vielen Dank.

Bearbeiten:
.__ So ist es möglich! Tom Lords Antwort macht das, was ich mit regulären Ausdrücken brauchte, also habe ich sie als richtige Antwort auf meine Frage markiert. 

Kurz nachdem ich diese Frage gepostet hatte, wurde mir klar, dass ich nicht richtig dachte. Da jeder andere Input des Projekts mit Regex gut "validierbar" war, ging ich sofort davon aus, dass ich diesen auch mit validieren konnte. 

Es stellte sich heraus, dass ich das einfach tun könnte: 

const validate = function(value) {
    const v = value.replace(/\s/g, '')
    const regex = new RegExp('^\\d{5}$');
    return regex.test(v);
}  

Vielen Dank für die coolen Antworten und Ideen! :) 

Edit2: Ich habe vergessen, ein möglicherweise recht wichtiges Detail zu erwähnen, das heißt, dass die Eingabe begrenzt ist, sodass der Benutzer nur bis zu 6 Zeichen eingeben kann. Entschuldigen Sie.

18
EyfI

Hinweis: Die Verwendung eines regulären Ausdrucks zur Lösung dieses Problems ist möglicherweise nicht die beste Antwort. Wie unten beantwortet Mit einer einfachen Funktion ist es möglicherweise einfacher, nur die Ziffern und Leerzeichen zu zählen!

Da die Frage jedoch eine Regex-Antwort erforderte und in einigen Szenarien möglicherweise gezwungen wird, dies mit einem Regex zu lösen (z. B. wenn Sie an die Implementierung einer bestimmten Bibliothek gebunden sind), gilt Folgendes Antwort kann hilfreich sein:

Dieser reguläre Ausdruck entspricht Zeilen mit genau 5 Ziffern:

^(?=(\D*\d){5}\D*$)

Dieser reguläre Ausdruck entspricht Zeilen, die ein optionales Leerzeichen enthalten:

^(?=[^ ]* ?[^ ]*$)

Wenn wir sie zusammenfügen, nd auch sicherstellen, dass die Zeichenfolge nur Ziffern und Leerzeichen enthält ​​([\d ]*$) , wir bekommen:

^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$

Sie können auch [\d ]{5,6} Anstelle von [\d ]* Am Ende dieses Musters verwenden, um den gleichen Effekt zu erzielen.

Demo

Erklärung:

Dieser reguläre Ausdruck verwendet Lookaheads . Hierbei handelt es sich um Mustervergleiche mit der Breite Null. Dies bedeutet, dass beide Teile des Musters am Anfang der Zeichenfolge "verankert" sind.

  • \d Bedeutet "eine beliebige Ziffer" und \D Bedeutet "eine beliebige keine Ziffer".

  • bedeutet "Leerzeichen" und [^ ] bedeutet "any non-space".

  • Das \D*\d Wird fünfmal wiederholt, um sicherzustellen, dass sich genau fünf Ziffern in der Zeichenfolge befinden.

Hier ist eine Visualisierung des Regex in Aktion:

regex visualisation

Beachten Sie, dass Sie stattdessen \s Und \S Verwenden könnten, wenn das "optionale Leerzeichen" Tabulatoren enthalten soll.


Update: Da diese Frage anscheinend ziemlich viel Anklang gefunden hat, wollte ich etwas über diese Antwort klarstellen.

Zu meiner obigen Antwort gibt es mehrere "einfachere" Variantenlösungen, wie zum Beispiel:

// Only look for digits and spaces, not "non-digits" and "non-spaces":
^(?=( ?\d){5} *$)(?=\d* ?\d*$)

// Like above, but also simplifying the second lookahead:
^(?=( ?\d){5} *$)\d* ?\d*

// Or even splitting it into two, simpler, problems with an "or" operator: 
^(?:\d{5}|(?=\d* \d*$).{6})$

Demos jeder Zeile oben: 12

Oder sogar, wenn wir annehmendass die Zeichenfolge nicht mehr als 6 Zeichen enthält ​​dann sogar nur das reicht aus:

^(?:\d{5}|\d* \d*)$

In diesem Sinne, warum könnte möchten Sie die ursprüngliche Lösung für ähnliche Probleme verwenden? Weil es generisch ist . Sehen Sie sich noch einmal meine ursprüngliche Antwort an, die mit Leerzeichen neu geschrieben wurde:

^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$)  # Must contain 0 or 1 spaces
[\d ]*$            # Must contain ONLY digits and spaces

Dieses Muster der Verwendung aufeinanderfolgender Vorausschauen kann verwendet werden in verschiedenen Szenarien , um Muster zu schreiben, die hochstrukturiert und (möglicherweise überraschenderweise) leicht zu erweitern sind.

Angenommen, die Regeln haben sich geändert und Sie wollten nun 2-3 Leerzeichen, 1 . Und eine beliebige Anzahl von Bindestrichen abgleichen. Es ist eigentlich sehr einfach, den regulären Ausdruck zu aktualisieren:

^
(?=(\D*\d){5}\D*$)       # Must contain exactly 5 digits
(?=([^ ]* ){2,3}[^ ]*$)  # Must contain 2 or 3 spaces
(?=[^.]*\.[^.]*$)        # Must contain 1 period
[\d .-]*$   # Must contain ONLY digits, spaces, periods and hyphens

... Zusammenfassend gibt es also gibt ​​"einfachere" reguläre Ausdrücke und möglicherweise eine bessere nicht reguläre Lösung für das spezifische Problem von OP. Ich habe jedoch ein allgemeines, erweiterbares Entwurfsmuster für übereinstimmende Muster dieser Art bereitgestellt.

19
Tom Lord

Ich schlage vor, zunächst nach genau fünf Zahlen zu suchen, ^\d{5}$ OR, um ein Leerzeichen zwischen den Zahlen ^(?=\d* \d*$) zwischen sechs Zeichen .{6}$ vorauszusehen.

Die Kombination dieser Teilausdrücke ergibt ^\d{5}$|^(?=\d* \d*$).{6}$:

let regex = /^\d{5}$|^(?=\d* \d*$).{6}$/;

console.log(regex.test('00000'));   // true
console.log(regex.test(' 00000'));  // true
console.log(regex.test('00000 '));  // true
console.log(regex.test('00 000'));  // true
console.log(regex.test('  00000')); // false
console.log(regex.test('00000  ')); // false
console.log(regex.test('00  000')); // false
console.log(regex.test('00 0 00')); // false
console.log(regex.test('000 000')); // false
console.log(regex.test('0000'));    // false
console.log(regex.test('000000'));  // false
console.log(regex.test('000 0'));   // false
console.log(regex.test('000 0x'));  // false
console.log(regex.test('0000x0'));  // false
console.log(regex.test('x00000'));  // false

Alternativ passen Sie die Teilausdrücke separat an, z.

/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)
8
le_m

Dies erscheint mir intuitiver und ist O (n)

function isInputValid(input) {
    const length = input.length;
    if (length != 5 && length != 6) {
        return false;
    }

    let spaceSeen = false;
    let digitsSeen = 0;
    for (let character of input) {
        if (character === ' ') {
            if (spaceSeen) {
                return false;
            }
            spaceSeen = true;
        }
        else if (/^\d$/.test(character)) {
            digitsSeen++;
        }
        else {
            return false;
        }
    }

    return digitsSeen == 5;
}
7
JonathanR

Hier ist eine einfache Regex, um den Job zu erledigen:

^(?=[\d ]{5,6}$)\d*\s?\d*$

Erläuterung:

^ bestätigt die Position am Anfang der Zeichenfolge

Positiver Lookahead (? = [\ D] {5,6} $)

Behaupten Sie, dass der Regex unten übereinstimmt

Übereinstimmung mit einem einzelnen Zeichen in der Liste unter [\ d] {5,6}

{5,6} Quantifier - Übereinstimmungen zwischen 5 und 6 Mal, so oft wie möglich, zurückgeben, wenn nötig (gierig)

\ d entspricht einer Ziffer (gleich [0-9]) stimmt mit dem Zeichen wörtlich überein (Groß- und Kleinschreibung wird berücksichtigt)

$ bestätigt die Position am Ende der Zeichenfolge \d * entspricht einer Ziffer (gleich [0-9])

  • Quantifier - Übereinstimmungen zwischen null und unbegrenzten Zeiten, so oft wie möglich, bei Bedarf zurückgeben (gierig)

\ s entspricht einem beliebigen Leerzeichen (gleich [\ r\n\t\f\v])

\ d * entspricht einer Ziffer (gleich [0-9])

  • Quantifier - Übereinstimmungen zwischen null und unbegrenzten Zeiten, so oft wie möglich, bei Bedarf zurückgeben (gierig)

$ bestätigt die Position am Ende der Zeichenfolge

1
John Smith

Sie können es in zwei Hälften teilen:

var input = '0000 ';

if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
  console.log('Match');

1
Thomas Ayoub
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
  alert("valid");
}

Sie können einfach die Länge überprüfen und ob es eine gültige Nummer ist ...

0
Jonas Wilms

So würde ich es ohne Regex tun:

string => [...string].reduce(
    ([spaces,digits], char) =>
        [spaces += char == ' ', digits += /\d/.test(char)],
    [0,0]
).join(",") == "1,5";
0
corvus_192