RegExp.exec () gibt sporadisch NULL zurück

83

Ich bin ernsthaft verrückt danach und habe bereits unverhältnismäßig viel Zeit damit verbracht, herauszufinden, was hier vor sich geht. Also bitte hilf mir =)

Ich muss einige RegExp-Übereinstimmungen von Zeichenfolgen in JavaScript durchführen. Leider verhält es sich sehr seltsam. Dieser Code:

var rx = /(cat|dog)/gi;
var w = new Array("I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.");

for (var i in w) {
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    }else{
        document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
}

Gibt "Katze" und "Hund" für die ersten beiden Elemente zurück, wie es sein sollte, aber dann exec()kehren einige Anrufe zurück null. Ich verstehe nicht warum.

Ich habe hier eine Geige gepostet , in der Sie den Code ausführen und bearbeiten können.

Und bis jetzt habe ich dies in Chrome und Firefox versucht.

Prost!

/ Christofer

cpak
quelle
es scheitert nur an einem "I have a cat and a dog too.", wie es scheint
SilentGhost
exec gibt null zurück, wenn eine Übereinstimmung beabsichtigt ist, weshalb sie aus irgendeinem Grund nicht übereinstimmt.
Martin Jespersen

Antworten:

78

Oh, hier ist es. Da Sie Ihren Regex global definieren, stimmt er zuerst catund beim zweiten Durchgang der Schleife überein dog. Im Grunde müssen Sie also auch nur Ihren regulären Ausdruck (den internen Zeiger) zurücksetzen. Vgl. Dies:

var w = new Array("I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.");

for (var i in w) {
    var rx = /(cat|dog)/gi;
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<p>" + i + "<br/>INPUT: " + w[i] + "<br/>MATCHES: " + w[i].length + "</p>");
    }else{
        document.writeln("<p><b>" + i + "<br/>'" + w[i] + "' FAILED.</b><br/>" + w[i].length + "</p>");
    }
    document.writeln(m);
}
SilentGhost
quelle
da haben wir es, ich war zu langsam :)
Martin Jespersen
ah süß! Ich hätte eine Weile gebraucht, um das herauszufinden. Vielen Dank!
Pak
Das hat mir viel Zeit gespart. Vielen Dank!
Thomas Johansen
Dieses Problem lässt mich am Leben zweifeln.
GZ Xue
Ich habe das Gefühl, ich sollte einfach meinen Gehaltsscheck zurückgeben
cgatian
71

Das Regex-Objekt verfügt über eine Eigenschaft, lastIndexdie beim Ausführen aktualisiert wird exec. Wenn Sie also die Regex für z. B. "Ich habe auch eine Katze und einen Hund." Ausführen, lastIndexwird diese auf 12 gesetzt . Wenn Sie das nächste Mal execdasselbe Regex-Objekt ausführen , wird ab Index 12 gesucht. Sie müssen also die lastIndexEigenschaft zurücksetzen zwischen jedem Lauf.

Frode
quelle
Bah, diese Seite ist zu schnell für mich. +1 für SilentGhost :-)
Frode
8
Danke für die Erklärung! Es hilft sehr, indem es myRe.lastIndex = 0;für die spätere Verwendung eingestellt wird.
Antony
1
Wow, vielen Dank für den Hinweis mit dem lastIndex, der mich wirklich verrückt gemacht hat!
Dave0688
1
Ich denke, dies sollte die richtige Antwort sein, da es der besten Praxis folgt, dasselbe Regex-Objekt
wiederzuverwenden
Stimmen Sie zu, dass dies die richtige Antwort sein sollte. Es verwendet dasselbe Regex-Objekt und erklärt auch die interne Mechanik. OP sollte eine Änderung in Betracht ziehen.
Sean Coley
31

Zwei Dinge:

  1. Die erwähnte Notwendigkeit des Zurücksetzens bei Verwendung des g(globalen) Flags. Um dies zu lösen, habe ich empfohlen, einfach 0dem lastIndexMitglied des RegExpObjekts zuzuweisen . Dies hat eine bessere Leistung als das Zerstören und Wiederherstellen.
  2. Seien Sie vorsichtig beim Einsatz inStichwort, um ein zu gehenArray Objekt, weil zu unerwarteten Ergebnissen mit einigen Libs führen kann. Manchmal sollten Sie sich bei jemandem wie erkundigen isNaN(i), oder wenn Sie wissen, dass es keine Löcher hat, verwenden Sie den Klassiker for loop.

Der Code kann sein:

var rx = /(cat|dog)/gi;
w = ["I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat."];

for (var i in w)
 if(!isNaN(i))        // Optional, check it is an element if Array could have some odd members.
  {
   var m = null;
   m = rx.exec(w[i]); // Run
   rx.lastIndex = 0;  // Reset
   if(m)
    {
     document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    } else {
     document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
  }
ESL
quelle
1
Dies sollte die richtige Antwort sein. Die Einstellung rx.lastIndex = 0ist viel besser als das RegEx-Objekt innerhalb der Schleife neu zu erstellen.
Minoru
4

Ich hatte ein ähnliches Problem nur mit / g, und die hier vorgeschlagene Lösung funktionierte in FireFox 3.6.8 nicht für mich. Ich habe mein Skript zum Arbeiten gebracht

var myRegex = new RegExp("my string", "g");

Ich füge dies hinzu, falls jemand anderes das gleiche Problem hat, das ich mit der obigen Lösung gemacht habe.

Don
quelle