2012-11-30 7 views
5

Ho fatto un semplice codice per l'acquisizione di un certo gruppo in una stringa:Regex in Javascript non è così goloso come dovrebbe?

/[a-z]+([0-9]+)[a-z]+/gi (n chars , m digts , k chars). 

code:

var myString='aaa111bbb222ccc333ddd'; 
var myRegexp=/[a-z]+([0-9]+)[a-z]+/gi; 

var match=myRegexp.exec(myString); 
console.log(match) 

while (match != null) 
{ 
    match = myRegexp.exec(myString); 
    console.log(match) 
} 

Il risultato sono stati:

["aaa111bbb", "111"] 
["ccc333ddd", "333"] 
null 

Ma aspettate un minuto, Perché non ha provato la parte bbb222ccc?

Voglio dire, ha visto la aaa111bbb ma poi si dovrebbe avere provare il bbb222ccc ... (Questo è goloso!)

Che cosa mi manca?

anche

guardando

while (match != null) 
    { 
     match = myRegexp.exec(myString); 
     console.log(match) 
    } 

come si è progredito al secondo risultato? all'inizio c'era:

var match = myRegexp.exec (myString);

più tardi (in un ciclo while)

match=myRegexp.exec(myString); 
match=myRegexp.exec(myString); 

è la stessa linea ... dove va a ricordare che il risultato prima era già mostrato?

+8

Poiché l'indice dopo la prima partita è alla fine della prima partita del bbb era già passato e nulla è lasciato per abbinare tranne il resto della stringa che è '" ccc333ddd "'. Greedy significa che '+' cercherà di abbinare il più possibile senza tener conto che la prossima parte della regex potrebbe farcela. – Esailija

+0

ciao @Esailija sì, l'ho già capito. ma se è avido come si dice, non lo è. –

+0

@Esailija si prega di incollare il tuo commento come risposta. –

risposta

4

.exec è di stato quando si utilizza il flag g. Lo stato viene mantenuto nella proprietà .lastIndex dell'oggetto regex.

var myString = 'aaa111bbb222ccc333ddd'; 
var myRegexp = /[a-z]+([0-9]+)[a-z]+/gi; 
var match = myRegexp.exec(myString); 
console.log(myRegexp.lastIndex); //9, so the next `.exec` will only look after index 9 
while (match != null) { 
    match = myRegexp.exec(myString); 
    console.log(myRegexp.lastIndex); 
} 

Lo stato può essere resettato modificando .lastIndex a 0 o execing una stringa differente. re.exec(""), ad esempio, ripristinerà lo stato perché lo stato è stato mantenuto per 'aaa111bbb222ccc333ddd'.

Lo stesso vale per il metodo .test, quindi non utilizzare mai il flag g con un'espressione regolare utilizzata per .test se si preferisce non avere sorprese. Vedere https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec

+0

vuol dire che se non avessi mantenuto la regex in una variabile, e avessi sempre usato raw '/ [az] + ([0-9] +) [az] +/', non avrebbe ricordato l'indice? –

+2

@RoyiNamir si, quando crei un nuovo oggetto regexp, non ha ancora nessuno stato. In altre parole, '/[a-z]+([0-9]+)[a-z]+/gi.lastIndex === 0' alwys – Esailija

+0

Non ho capito la parte' test'. perché non dovrei usare il test con [g]? perché produce> 1 risultati? –

2

È inoltre possibile aggiornare manualmente la proprietà lastIndex:

var myString='aaa111bbb222ccc333ddd'; 
var myRegexp=/[a-z]+([0-9]+)[a-z]+/gi; 

var match=myRegexp.exec(myString); 
console.log(match); 

while (match != null) 
{ 
    myRegexp.lastIndex -= match[0].length - 1; // Set the cursor to the position just after the beginning of the previous match 
    match = myRegexp.exec(myString); 
    console.log(match) 
} 

Vedi questo link MDN exec.


EDIT:

Tra l'altro la tua regex dovrebbe essere: /[a-z]{3}([0-9]{3})[a-z]{3}/gi

+0

edited.thanks !! –