2009-05-09 10 views
60

Perché Javascript sub-partite smettere di funzionare quando il modificatore g è impostato?JavaScript espressioni regolari e sub-match

var text = 'test test test test'; 

var result = text.match(/t(e)(s)t/); 
// Result: ["test", "e", "s"] 

Le opere di cui sopra bene, result[1] è "e" e result[2] è "s".

var result = text.match(/t(e)(s)t/g); 
// Result: ["test", "test", "test", "test"] 

Quanto sopra ignora i miei gruppi di acquisizione. La seguente è l'unica soluzione valida?

var result = text.match(/test/g); 
for (var i in result) { 
    console.log(result[i].match(/t(e)(s)t/)); 
} 
/* Result: 
["test", "e", "s"] 
["test", "e", "s"] 
["test", "e", "s"] 
["test", "e", "s"] 
*/ 

risposta

91

Utilizzando String s' match() funzione non restituirà i gruppi catturato se il modificatore globale è impostato, come hai scoperto.

In questo caso, si desidera utilizzare un oggetto e chiamare la sua funzione exec(). String 's match() è quasi identico a RegExp' exec() funzione s ... tranne che in casi come questi. Se il modificatore globale è impostata, la normale funzione match() non tornerà gruppi catturati, mentre exec() funzione RegExp s'. (Notato here, tra gli altri luoghi.)

Un'altra cattura ricordare è che exec() non restituisce le partite in un unico grande partite array si continua a tornare fino a quando non si esaurisce, nel qual caso restituisce null.

Così, per esempio, si potrebbe fare qualcosa di simile:

var pattern = /t(e)(s)t/g; // Alternatively, "new RegExp('t(e)(s)t', 'g');" 
var match;  

while (match = pattern.exec(text)) { 
    // Do something with the match (["test", "e", "s"]) here... 
} 

Un'altra cosa da notare è che RegExp.prototype.exec() e RegExp.prototype.test() eseguire l'espressione regolare sulla stringa fornita e riportare il primo risultato. Ogni chiamata sequenziale passerà attraverso il set di risultati aggiornando RegExp.prototype.lastIndex in base alla posizione corrente nella stringa.

Ecco un esempio: // ricordare ci sono 4 partite l'esempio e modello. lastIndex inizia da 0

pattern.test(text); // pattern.lastIndex = 4 
pattern.test(text); // pattern.lastIndex = 9 
pattern.exec(text); // pattern.lastIndex = 14 
pattern.exec(text); // pattern.lastIndex = 19 

// if we were to call pattern.exec(text) again it would return null and reset the pattern.lastIndex to 0 
while (var match = pattern.exec(text)) { 
    // never gets run because we already traversed the string 
    console.log(match); 
} 

pattern.test(text); // pattern.lastIndex = 4 
pattern.test(text); // pattern.lastIndex = 9 

// however we can reset the lastIndex and it will give us the ability to traverse the string from the start again or any specific position in the string 
pattern.lastIndex = 0; 

while (var match = pattern.exec(text)) { 
    // outputs all matches 
    console.log(match); 
} 

È possibile trovare informazioni su come utilizzare gli oggetti RegExpon the MDN (nello specifico, ecco la documentazione per the exec() function).

+3

utilizzando exec non sembra ascoltare il modificatore di g, ma supporta sub-match/gruppi. Così il risultato sarebbe la prima partita (ignora sostanzialmente la g modificatore) –

+0

Aggiunto un chiarimento al riguardo, si deve chiamare exec() più volte per ottenere i più corrispondenze. – hbw

+2

Non la soluzione più elegante. Mi aspettavo un'uscita un po 'come questo: [ \t [ "test", "e", "s"], \t [ "test", "e", "s"], \t [" test "," e "," s "], \t [" test "," e "," s "] ] –