Jaka jest różnica między funkcją exec () RegExp a funkcją match () String?


122

Jeśli uruchomię to:

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

Rozumiem:

["a", "a"]

Ale jeśli uruchomię to:

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

Wtedy otrzymuję oczekiwany wynik tego:

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

Co za różnica?


4
wykonujesz pętlę, execaby uzyskać wszystkie pod-selekcje.
zzzzBov

2
Zwróć uwagę, że drugie +nie jest potrzebne, ponieważ matchzwróci już wszystkie wyrażenia podrzędne. .execzwraca tylko jeden za każdym razem, więc to też nie jest potrzebne +.
pimvdb

3
Co więcej, zagnieżdżone kwantyfikatory, takie jak te dwa plusy, powinny być używane niezwykle ostrożnie, ponieważ łatwo prowadzą do katastrofalnego cofania się .
Marius Schulz,

1
@MariusSchulz Dzięki za link. To doprowadziło mnie do poznania kwantyfikatorów zaborczych i grupowania atomowego. Bardzo fajne rzeczy do zrozumienia.
Justin Warkentin

Odpowiedzi:


118

execz globalnym wyrażeniem regularnym ma być używane w pętli, ponieważ nadal pobiera wszystkie dopasowane wyrażenia podrzędne. Więc:

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 robi to za Ciebie i odrzuca przechwycone grupy.


39
Mam coś do dodania do tej odpowiedzi, nie należy umieszczać dosłownego wyrażenia regularnego w warunku while, w ten sposób, while(match = /[^\/]+/g.exec('/a/b/c/d')bo inaczej utworzy to nieskończoną pętlę !. Jak wyraźnie stwierdzono w MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...
yeyo

7
@yeyo: Dokładniej, musi to być ten sam obiekt wyrażenia regularnego. Dosłowny tego nie osiąga.
Ry-

@ Ry- Myślę, że należy zauważyć, że to zachowanie zostało wprowadzone w ES5. Przed ES5 new RegExp("pattern")i /pattern/oznaczało różne rzeczy.
Robert

75

Jedno zdjęcie jest lepsze, wiesz ...

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))

Zobacz różnicę?

Uwaga: Aby podkreślić, zauważ, że przechwycone grupy (np.: A, A) są zwracane po dopasowanym wzorcu (np .: aA), to nie jest tylko dopasowany wzorzec.


28

/regex/.exec()zwraca tylko pierwsze znalezione dopasowanie, natomiast "string".match()zwraca je wszystkie, jeśli użyjesz gflagi w wyrażeniu regularnym.

Zobacz tutaj: exec , match .


23

Jeśli twoje wyrażenie regularne jest globalne i przechwytujesz, musisz użyć exec. Mecz nie zwróci wszystkich zdobytych punktów.

Dopasowywanie świetnie sprawdza się podczas dopasowywania (nie do przechwytywania). Uruchamiasz go raz i daje tablicę wszystkich dopasowań. (chociaż jeśli wyrażenie regularne nie jest globalne, dopasowanie pokaże dopasowanie, po którym nastąpi przechwycenie)

Exec jest tym, czego używasz podczas przechwytywania i za każdym razem, gdy jest wykonywany, daje dopasowanie, a następnie przechwytywanie. (dopasowanie będzie zachowywać się w sposób zapewniający pełne dopasowanie, po którym nastąpi przechwycenie, tylko wtedy, gdy wyrażenie regularne nie jest globalne).

Innym zastosowaniem z Exec, jest pobranie indeksu lub pozycji dopasowania. Kiedy masz zmienną dla swojego wyrażenia regularnego, możesz użyć .lastIndex i uzyskać pozycję dopasowania. Obiekt regex ma .lastIndex, a obiekt regex jest tym, co robisz .exec. Dopasowywanie kropek jest wykonywane na łańcuchu i nie będzie można wtedy wykonać obiektu regex dot lastIndex

Łańcuch ma funkcję dopasowania, do której przekazywane jest wyrażenie regularne. A regex ma funkcję exec i jest przekazywany ciąg

exec, uruchamiasz wiele razy. dopasować biegasz raz

Dobrze jest użyć dopasowania, gdy nie przechwytujesz, a podczas przechwytywania możesz użyć exec, które jest potężniejsze, ponieważ jest dobre do przechwytywania, ale jeśli użyłeś dopasowania podczas przechwytywania, zobacz, że pokazuje przechwytywania, gdy wyrażenie regularne nie jest globalne, ale tak nie jest nie pokazuje ujęć, gdy wyrażenie regularne jest globalne.

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

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

Inną rzeczą jest to, że jeśli używasz exec, uwaga, która jest wywoływana na wyrażeniu regularnym, to jeśli użyłeś zmiennej dla tego wyrażenia regularnego, masz większą moc

Nie otrzymujesz dopasowań, jeśli nie używasz zmiennej dla wyrażenia regularnego, więc użyj zmiennej dla wyrażenia regularnego, gdy używasz 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
>

Za pomocą exec możesz uzyskać „indeks” dopasowania

> 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
>

Więc jeśli chcesz indeksować lub przechwytywać, użyj exec (pamiętaj, że jak widzisz, z "indeksem", "indeks", który podaje, jest tak naprawdę n-tym wystąpieniem, liczy się od 1. Więc możesz wyprowadzić właściwe indeks przez odjęcie 1. I jak widać daje 0 - lastIndex 0 - dla nie znaleziono).

A jeśli chcesz dopasować rozciąganie, możesz go użyć podczas przechwytywania, ale nie wtedy, gdy wyrażenie regularne jest globalne, a kiedy to robisz, to zawartość tablicy nie jest wszystkimi dopasowaniami, ale są pełne mecz, po którym następuje przechwytywanie.


Tak, zrozumienie działania r.lastIndexjest kluczowym czynnikiem do zrozumienia różnicy między execi match.
start

@barlop "Dopasowanie nie pasuje do wszystkich ujęć", poważnie? „a, b, c, aa, bb, cc” .match (/ (\ w +) / g) => [„a”, „b”, „c”, „aa”, „bb”, „cc” ]. Jak wyjaśnić, że zapisał je wszystkie w pamięci podręcznej?
MrHIDEn

@barlop If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.Mam to na konsoli. Po prostu skopiuj / wklej "a,b,c,aa,bb,cc".match(/(\w+)/g);Opera, Firefox.
MrHIDEn

@MrHIDEn Nie użyłbym języka, którego użyłeś w złym cytacie. Liczy się to, co jest pokazane i co jesteśmy w stanie zobaczyć… czy za kulisami jest cache również nie ma znaczenia. Minęło trochę czasu, odkąd się temu przyjrzałem, ale nie pokazuje wszystkich ujęć. Nawet jeśli zrobisz swój przykład "a,b,c,aa,bb,cc".match(/(\w+)/g) To, co się tam dzieje, pokazuje wszystkie mecze i tak się składa, że ​​przechwyciłeś każdy mecz, więc gdyby miał pokazać wszystkie ujęcia, wyglądałoby to dokładnie tak samo (
cntd

(cntd) Więc może myślisz, że to pokazuje przechwytywanie, ale tak nie jest, pokazuje mecze
barlop

6

.Match () funkcja str.match(regexp)będzie wykonać następujące czynności:

  • jeśli jest dopasowanie, zwróci:
    • jeśli gflaga jest użyta w wyrażeniu regularnym: zwróci wszystkie podciągi (ignorując grupy przechwytywania)
    • jeśli gflaga nie jest używana w wyrażeniu regularnym: zwróci to samo coregexp.exec(str)
  • jeśli nie ma dopasowania, zwróci:
    • null

Przykłady funkcji .match () używającej gflagi:

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

A .match () bez gflagi jest równoważne .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

.Exec () funkcja regexp.exec(str)będzie wykonać następujące czynności:

  • jeśli jest dopasowanie, zwróci:
    • jeśli gflaga jest użyta w wyrażeniu regularnym: zwróci (za każdym razem, gdy jest wywoływana) : [N_MatchedStr, N_Captured1, N_Captured2, ...]następnego Ndopasowania. Ważne: nie przejdzie do następnego dopasowania, jeśli obiekt wyrażenia regularnego nie jest przechowywany w zmiennej (musi to być ten sam obiekt)
    • jeśli gflaga nie jest używana w wyrażeniu regularnym: zwróci to samo, co gdyby miała gflagę i została wywołana po raz pierwszy i tylko raz.
  • jeśli nie ma dopasowania, zwróci:
    • null

Przykład .exec () (zapisane wyrażenie regularne + użycie gflagi = zmienia się przy każdym wywołaniu):

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
}

Przykłady .exec (), gdy nie zmienia się przy każdym wywołaniu:

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

Czasami regex.exec () zajmie znacznie więcej czasu niż string.match ().

Warto wspomnieć, że jeśli wynik string.match () i regex.exec () jest taki sam (np. Gdy nie używa się flagi \ g), regex.exec () zajmie miejsce od x2 do x30, a następnie string. mecz():

Dlatego w takich przypadkach użycie metody „new RegExp (). Exec ()” powinno być stosowane tylko wtedy, gdy potrzebujesz globalnego wyrażenia regularnego (tj. Aby wykonać więcej niż jeden raz).


1
Czy masz punkt odniesienia?
Sơn Trần-Nguyễn
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.