2012-06-13 20 views
12

Mögliche Duplizieren:
Interesting test of Javascript RegExp
Regular expression test can't decide between true and false (JavaScript)Warum verhält sich dieselbe RegExp anders?

Example of issue. Wenn ich inline lief, waren die Ergebnisse wie erwartet. Wenn es jedoch als Variable gespeichert wird, überspringt es das Element der mittleren Spannweite.

// Inline RegExp 
function getToggleClasses() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (/toggler/g.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Inline: " + toggler.length; 
} 

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     tester = /toggler/g, 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
​ 

Mark up:

<span class="toggler">A</span> 
<span class="toggler">B</span> 
<span class="toggler">C</span> 

Gegeben: ich es verstehe, ist kein Grund, eine RegExp zu verwenden, um diesen Vergleich zu tun und ich verstehe auch, wie groß Bibliotheken wie jQuery sind. Ich weiß auch, dass die g in diesem Fall nicht benötigt wird.

Ich kann nicht verstehen, warum diese beiden Methoden jemals unterschiedliche Ergebnisse zurückgeben sollten.

+0

Dies ist nur eine persönliche Vorliebe, aber ich denke, es würde die Klarheit ein wenig verbessern, um Klammern um ein Regex-Literal zu setzen, das Flags hat, wenn eine Funktion auf dem Literal aufgerufen wird. – JAB

+1

@apsillers, Sie sind richtig. Was hast du gesucht, um diese zu finden? Ich konnte nicht herausfinden, was ich suchen sollte, um die Ergebnisse zu erhalten, nach denen ich suchte. – Joe

+0

Ich habe ein bisschen geschummelt und nach '[javascript] regex test lastindex' gesucht - ich war ziemlich sicher, dass eine Frage wie diese schon einmal gestellt wurde und ich wusste, dass die Antwort den Text' lastIndex' enthalten würde. Dies ist ein guter Fall, der zeigt, dass die Existenz einer doppelten Frage nicht notwendigerweise ein Hinweis darauf ist, dass der Fragesteller nachlässig war; Sie haben eine gut formulierte Frage für ein schwierig zu suchendes Problem gestellt. – apsillers

Antwort

9

RegExp Instanzen sind Stateful, so die Wiederverwendung von ihnen kann zu unerwartetem Verhalten führen. In diesem speziellen Fall liegt das daran, dass die Instanz global lautet:

dass der reguläre Ausdruck für alle möglichen Übereinstimmungen in einer Zeichenfolge getestet werden sollte.

Das ist jedoch nicht der einzige Unterschied, der durch die Verwendung von g verursacht wird. From RegExp.test @ MDN:

Wie bei exec (oder mit ihm in Kombination), test mehrere Male auf der gleichen globalen regulären Ausdruck Instanz aufgerufen hinter dem vorherigen Spiel voranbringen wird.


Remove the g flag oder set lastIndex to 0 (danke, @zzzzBov).

+3

oder set 'lastIndex' auf' 0' ... – zzzzBov

+0

@zzzzBov guter Punkt, bearbeitet. –

3

/g ist nicht benötigt und sollte in diesem Fall nicht verwendet werden.

Das Verhalten unterscheidet sich in diesen Fällen, weil das Regex-Objekt in der "Inline" -Fall bei jeder Wiederholung der Schleife neu erstellt wird. While in der Variablen wird einmal erstellt und behält ihren Status (lastIndex) zwischen Schleifeniterationen bei.

die var in die Schleife bewegen, und Sie werden das gleiche Ergebnis:

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    var tester = /toggler/g; 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
+1

Ja, das habe ich. Aber warum bin ich sehr neugierig. Weil '/toggler/g.test('toggler '); // true' – Joe

+1

@Joe, erklärt. – Qtax

+1

@Joe, hast du in der Frage geschrieben * "Ich weiß auch, dass das' g' benötigt wird "*, deshalb behaupte ich, dass es nicht ist. – Qtax

1

Der Regex behält eine Variable bei, die lastIndex genannt wird, das der Index ist, um die nächste Suche zu starten. Von MDN:

Wie bei exec (oder mit ihm in Kombination), test mehrere Male auf der gleichen globalen regulären Ausdruck Instanz aufgerufen hinter dem vorherigen Spiel voranbringen wird.

Wenn Sie einen Inline-regex für jede Iteration zu definieren, wird der Zustand verloren und lastIndex ist immer 0, weil Sie eine frische regex jedes Mal haben. Wenn Sie die Regex als verlässlich speichern, wird die lastIndex als Endposition der letzten Übereinstimmung gespeichert. In diesem Fall wird die nächste Suche nach begin am Ende der nächsten Zeichenfolge ausgelöst, was zu einer fehlgeschlagenen Übereinstimmung führt. Wenn der dritte Vergleich kommt, wurde die lastIndex auf 0 zurückgesetzt, weil die Regex weiß, dass sie beim letzten Mal keine Ergebnisse erhalten hat.

Verwandte Themen