Qual è la differenza tra la funzione exec () di RegExp e la funzione match () di String?


122

Se eseguo questo:

/([^\/]+)+/g.exec('/a/b/c/d');

Ho capito:

["a", "a"]

Ma se eseguo questo:

'/a/b/c/d'.match(/([^\/]+)+/g);

Quindi ottengo il risultato atteso di questo:

["a", "b", "c", "d"]

Qual è la differenza?


4
fai un loop con execper ottenere tutte le sotto-selezioni.
zzzzBov

2
Nota che il secondo +non è necessario poiché matchrestituirà già tutte le sottoespressioni. .execne restituisce solo uno ogni volta, quindi non ne ha bisogno +.
pimvdb

3
Inoltre, quantificatori annidati come i due vantaggi dovrebbero essere usati con estrema attenzione perché portano facilmente a un backtracking catastrofico .
Marius Schulz

1
@MariusSchulz Grazie per il collegamento. Questo mi ha portato a conoscere i quantificatori possessivi e il raggruppamento atomico. Cose molto belle da capire.
Justin Warkentin

Risposte:


118

execcon un'espressione regolare globale è pensato per essere utilizzato in un ciclo, poiché recupererà comunque tutte le sottoespressioni corrispondenti. Così:

var re = /[^\/]+/g;
var match;

while (match = re.exec('/a/b/c/d')) {
    // match is now the next match, in array form.
}

// No more matches.

String.match fa questo per te e scarta i gruppi catturati.


39
Ho qualcosa da aggiungere a questa risposta, non si dovrebbe posizionare l'espressione regolare letterale nella condizione while, in questo modo while(match = /[^\/]+/g.exec('/a/b/c/d')o creerà un ciclo infinito !. Come è chiaramente indicato in MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
yeyo

7
@yeyo: Più specificamente, deve essere lo stesso oggetto espressione regolare. Un letterale non lo fa.
Ry-

@ Ry- Penso che si dovrebbe notare che questo comportamento è stato introdotto in ES5. Prima di ES5 new RegExp("pattern")e /pattern/significava cose diverse.
Robert,

75

Una foto è meglio, sai ...

re_once = /([a-z])([A-Z])/
re_glob = /([a-z])([A-Z])/g

st = "aAbBcC"

console.log("match once="+ st.match(re_once)+ "  match glob="+ st.match(re_glob))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))

Vedi la differenza?

Nota: per evidenziare, notare che i gruppi catturati (ad esempio: a, A) vengono restituiti dopo il modello abbinato (ad esempio: aA), non è solo il modello abbinato.


28

/regex/.exec()restituisce solo la prima corrispondenza trovata, mentre "string".match()restituisce tutte se si utilizza il gflag nella regex.

Vedi qui: exec , match .


23

Se la tua regex è globale e stai catturando, devi usare exec. Match non restituirà tutte le tue acquisizioni.

Match funziona alla grande per quando si esegue solo la corrispondenza (non l'acquisizione). Lo esegui una volta e fornisce un array di tutte le corrispondenze. (anche se se la regex non è globale, match mostrerà la corrispondenza seguita dalle acquisizioni)

Exec è ciò che usi durante l'acquisizione e ogni volta che viene eseguito fornisce la corrispondenza, seguita dalle acquisizioni. (match si comporterà in modo da fornire la corrispondenza completa seguita da acquisizioni, solo quando la regex non è globale).

Un altro utilizzo con Exec è ottenere l'indice o la posizione di una corrispondenza. Quando hai una variabile per la tua regex, puoi usare .lastIndex e ottenere la posizione della corrispondenza. Un oggetto regex ha .lastIndex e l'oggetto regex è ciò su cui esegui .exec. La corrispondenza del punto viene eseguita su una stringa e non sarai in grado di eseguire il punto oggetto regex lastIndex

Una stringa ha la funzione match, a cui viene passata una regex. E una regex, ha la funzione exec e viene passata una stringa

eseguito più volte. partita che corri una volta

È bene usare match quando non si acquisisce e durante l'acquisizione è possibile utilizzare exec che è più potente in quanto è utile per ottenere acquisizioni, ma se si utilizza match durante l'acquisizione, vedere che mostra acquisizioni quando la regex non è globale, ma non non mostra le catture quando la regex è globale.

> "azb".match(/a(z)b/);
[ "azb", "z" ]

> "azb".match(/a(z)b/g);
[ "azb" ]
>

Un'altra cosa è che se usi exec, nota che viene chiamato nella regex, quindi se hai usato una variabile per l'espressione regolare, hai più potere

Non ottieni le corrispondenze quando non usi la variabile per la regex, quindi usa la variabile per la regex, quando usi exec

> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
>
> /[a-c]/g.exec("abc")
[ "a" ]
> /[a-c]/g.exec("abc")
[ "a" ]
>

> var r=/[a-c]/g
> r.exec("abc")
[ "a" ]
> r.exec("abc")
[ "b" ]
> r.exec("abc")
[ "c" ]
> r.exec("abc")
null
>

E con exec, puoi ottenere l '"indice" della partita

> var r=/T/g
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
2
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
6
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
9
> r.exec("qTqqqTqqTq");
null
> r.lastIndex
0
>

Quindi, se vuoi gli indici o la cattura, usa exec (tieni presente che, come puoi vedere, con l '"indice", l' "indice" che fornisce è davvero un'ennesima occorrenza, conta da 1. Quindi potresti derivare il corretto index sottraendo 1. E come puoi vedere dà 0 - lastIndex di 0 - per non trovato).

E se vuoi estendere la corrispondenza, puoi usarla quando stai catturando, ma non quando la regex è globale, e quando lo fai per quello, allora i contenuti dell'array non sono tutte le corrispondenze, ma sono il pieno partita seguita dalle catture.


Sì, capire il funzionamento di r.lastIndexè il fattore chiave per capire la differenza tra exece match.
eseguito il

@barlop "La corrispondenza non corrisponde a tutte le acquisizioni", sul serio? "a, b, c, aa, bb, cc" .match (/ (\ w +) / g) => ["a", "b", "c", "aa", "bb", "cc" ]. Come spiegare che li ha memorizzati tutti nella cache?
MrHIDE il

@barlop l' If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.ho preso sulla console. Basta copiare / incollare "a,b,c,aa,bb,cc".match(/(\w+)/g);Opera, Firefox.
MrHIDE il

@MrHIDEn Non useresti la lingua che hai fatto nella citazione sbagliata. E ciò che conta è ciò che viene mostrato e ciò che siamo in grado di vedere .. anche se c'è qualche caching dietro le quinte non è rilevante. Ed è passato un po 'di tempo dall'ultima volta che ho esaminato questo aspetto, ma non mostra tutte le catture .. Anche se fai il tuo esempio "a,b,c,aa,bb,cc".match(/(\w+)/g) Quello che sta succedendo mostra tutte le corrispondenze, ed è il caso che tu abbia catturato ogni corrispondenza, quindi se mostrasse tutte le acquisizioni, apparirebbe esattamente lo stesso (cntd)
barlop

(cntd) Quindi forse stai pensando che stia mostrando le catture, ma non lo è, sta mostrando le partite
barlop

6

Il .match () la funzione str.match(regexp)farà il seguente:

  • se v'è una corrispondenza verrà restituito:
    • se il gflag è usato nella regexp: restituirà tutte le sottostringhe (ignorando i gruppi di cattura)
    • se il gflag non è usato nella regexp: restituirà lo stesso diregexp.exec(str)
  • se non c'è corrispondenza tornerà:
    • null

Esempi di .match () utilizzando il gflag:

var str = "qqqABApppabacccaba";
var e1, e2, e3, e4, e5;
e1 = str.match(/nop/g); //null
e2 = str.match(/no(p)/g); //null
e3 = str.match(/aba/g); //["aba", "aba"]
e4 = str.match(/aba/gi); //["ABA", "aba", "aba"]
e5 = str.match(/(ab)a/g); //["aba", "aba"] ignoring capture groups as it is using the g flag

E .match () senza gflag è equivalente a .exec () :

e1=JSON.stringify(str.match(/nop/))===JSON.stringify(/nop/.exec(str)); //true
//e2 ... e4 //true
e5=JSON.stringify(str.match(/(ab)a/))===JSON.stringify(/(ab)a/.exec(str)); //true

Il .exec () la funzione regexp.exec(str)farà il seguente:

  • se v'è una corrispondenza verrà restituito:
    • se la gbandiera è usata nella regexp: tornerà (per ogni volta che viene chiamata) : [N_MatchedStr, N_Captured1, N_Captured2, ...]della prossima Ncorrispondenza. Importante: non avanzerà nella corrispondenza successiva se l'oggetto regexp non è memorizzato in una variabile (deve essere lo stesso oggetto)
    • se la gbandiera non è usata nella regexp: restituirà lo stesso come se avesse una gbandiera e fosse chiamata per la prima volta e solo una volta.
  • se non c'è corrispondenza tornerà:
    • null

Esempio di .exec () (regexp memorizzato + utilizzando il gflag = cambia ad ogni chiamata):

var str = "qqqABApppabacccaba";
var myexec, rgxp = /(ab)a/gi;

myexec = rgxp.exec(str);
console.log(myexec); //["ABA", "AB"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //null

//But in this case you should use a loop:
var mtch, myRe = /(ab)a/gi;
while(mtch = myRe.exec(str)){ //infinite looping with direct regexps: /(ab)a/gi.exec()
    console.log("elm: "+mtch[0]+" all: "+mtch+" indx: "+myRe.lastIndex);
    //1st iteration = elm: "ABA" all: ["ABA", "AB"] indx: 6
    //2nd iteration = elm: "aba" all: ["aba", "ab"] indx: 12
    //3rd iteration = elm: "aba" all: ["aba", "ab"] indx: 18
}

Esempi di .exec () quando non cambia a ogni chiamata:

var str = "qqqABApppabacccaba", myexec, myexec2;

//doesn't go into the next one because no g flag
var rgxp = /(a)(ba)/;
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
//... ["aba", "a", "ba"]

//doesn't go into the next one because direct regexp
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
//... ["ABA", "AB"]

1

A volte regex.exec () impiegherà molto più tempo di string.match ().

Vale la pena ricordare che se il risultato di string.match () e regex.exec () è lo stesso (es: quando non si usa il flag \ g), regex.exec () prenderà da qualche parte tra x2 e x30 quindi string. incontro():

Pertanto in questi casi, utilizzando l'approccio di "new RegExp (). Exec ()" dovrebbe essere utilizzato solo quando è necessaria una regex globale (cioè per eseguire più di una volta).


1
Hai un punto di riferimento?
Sơn Trần-Nguyễn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.