RegExp'in exec () işlevi ile String'in match () işlevi arasındaki fark nedir?


122

Bunu çalıştırırsam:

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

Bunu anlıyorum:

["a", "a"]

Ama bunu çalıştırırsam:

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

Sonra bunun beklenen sonucunu alıyorum:

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

Fark ne?


4
exectüm alt seçimleri almak için birlikte dönersiniz.
zzzzBov

2
Tüm alt ifadeleri zaten döndüreceğinden ikinciye +gerek olmadığını unutmayın match. .execher seferinde yalnızca bir tane döndürür, bu yüzden buna da gerek kalmaz +.
pimvdb

3
Bunun da ötesinde, iki artı gibi iç içe yerleştirilmiş niceleyiciler son derece dikkatli kullanılmalıdır çünkü bunlar kolayca yıkıcı geri dönüşe yol açar .
Marius Schulz

1
@MariusSchulz Bağlantı için teşekkürler. Bu da beni iyelik niceliklendiricileri ve atomik gruplama hakkında bilgi edinmeye yöneltti. Anlamak için çok güzel şeyler.
Justin Warkentin

Yanıtlar:


118

execile genel bir düzenli ifade, eşleşen tüm alt ifadeleri almaya devam edeceği için bir döngüde kullanılması amaçlanmıştır. Yani:

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 bunu sizin için yapar ve yakalanan grupları atar.


39
Bu yanıta ekleyeceğim bir şey var, normal ifadeyi while koşulu içine koymamalıyım, while(match = /[^\/]+/g.exec('/a/b/c/d')yoksa sonsuz bir döngü oluşturacak !. MDN geliştiricisinde
gibi.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

7
@yeyo: Daha spesifik olarak, aynı normal ifade nesnesi olması gerekir. Kelimenin tam anlamıyla bunu başaramaz.
Ry-

@ Ry- Bence bu davranışın ES5'te tanıtıldığına dikkat edilmelidir. ES5'ten önce new RegExp("pattern")ve /pattern/farklı şeyler ifade ediyordu.
Robert

75

Bir resim daha iyidir, bilirsiniz ...

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

Farkı gör?

Not: Vurgulamak için, yakalanan grupların (örneğin: a, A) eşleşen modelden (örneğin: aA) sonra döndürüldüğüne dikkat edin, bu sadece eşleşen model değildir.


28

/regex/.exec()yalnızca bulunan ilk eşleşmeyi "string".match()döndürürken g, normal ifadede bayrağı kullanırsanız tümünü döndürür .

Buraya bakın: exec , match .


23

Normal ifadeniz globalse ve yakalıyorsanız, o zaman exec kullanmalısınız. Maç tüm yakalamalarınızı geri getirmeyecek.

Maç, sadece eşleştirme (yakalama değil) için harika çalışıyor. Bir kez çalıştırırsınız ve tüm eşleşmelerin bir dizisini verir. (ancak normal ifade genel değilse, bu durumda eşleşme, eşleşmeyi ve ardından yakalamaları gösterir)

Yürütme, yakalarken kullandığınız şeydir ve her yürütüldüğünde maçı verir ve ardından yakalamalar gelir. (Eşleşme, yalnızca normal ifade global olmadığında tam eşleşmeyi takiben yakalamalar verecek şekilde davranacaktır).

Exec ile başka bir kullanım, bir eşleşmenin dizinini veya konumunu almaktır. Normal ifadeniz için bir değişkeniniz olduğunda, .lastIndex'i kullanabilir ve eşleşmenin konumunu alabilirsiniz. Bir normal ifade nesnesi .lastIndex'e sahiptir ve normal ifade nesnesi de .exec üzerinde yaptığınız şeydir. Nokta eşleştirme bir dizede yapılır ve bu durumda normal ifade nesnesi nokta lastIndex yapamazsınız

Bir dize, bir normal ifadeden geçen match işlevine sahiptir. Ve bir normal ifade, exec işlevine sahiptir ve bir dize geçirilir

exec birden çok kez çalıştırırsınız. bir kez koştuğun maç

Yakalama yapmadığınızda ve yakalarken eşleşmeyi kullanmak iyidir, bu daha güçlüdür, çünkü yakalamalar için iyidir, ancak yakalarken eşleşmeyi kullandıysanız, normal ifade global olmadığında yakalamaları gösterdiğine bakın. Normal ifade global olduğunda yakalamaları gösterme.

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

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

Başka bir şey de, eğer exec kullanırsanız, normal ifadede çağrılan not edin, o zaman normal ifade için bir değişken kullandıysanız, daha fazla gücünüz olur.

Değişkeni normal ifade için kullanmadığınızda eşleşmeleri elde edemezsiniz, bu nedenle, exec kullanırken normal ifade için değişkeni kullanın

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

Ve exec ile, maçın "indeksini" alabilirsiniz

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

Dolayısıyla, dizinler veya yakalama istiyorsanız, o zaman exec kullanın (görebileceğiniz gibi, "dizin" ile birlikte verdiği "dizin" gerçekten n'inci bir oluşumdur, 1'den saymaktadır. Böylece doğru olanı türetebilirsiniz. 1'i çıkararak indeksleme. Ve gördüğünüz gibi 0 - lastIndex - 0 - bulunamadı.

Eşleşmeyi uzatmak istiyorsanız, onu yakalarken kullanabilirsiniz, ancak normal ifade global olduğunda kullanamazsınız ve bunun için yaptığınızda, dizinin içeriği tüm eşleşmeler değil, tamdır maç ve ardından yakalamalar.


Evet, çalışma anlayışı r.lastIndexarasındaki farkı anlamak önemli bir faktördür execve match.
runsun

@barlop "Maç tüm yakalamalarla eşleşmeyecek", cidden mi? "a, b, c, aa, bb, cc" .match (/ (\ w +) / g) => ["a", "b", "c", "aa", "bb", "cc" ]. Hepsini önbelleğe aldığını nasıl açıklayabilirim?
MrHIDEn

@barlop Konsolda If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.buldum. Sadece "a,b,c,aa,bb,cc".match(/(\w+)/g);Opera, Firefox'u kopyalayıp yapıştırın .
MrHIDEn

@MrHIDEn Yaptığın dili yanlış alıntıda kullanmaz mısın? Ve önemli olan, neyin gösterildiğidir ve ne görebildiğimizdir .. perde arkasında herhangi bir önbelleğe alma olup olmadığı da önemli değildir. Ve bu "a,b,c,aa,bb,cc".match(/(\w+)/g) konuya baktığımdan bu yana epey bir zaman geçti, ama tüm yakalamaları göstermiyor .. Örneğinizi yapsanız bile Orada olan tüm eşleşmeleri gösteriyor ve öyle oluyor ki her maçı yakaladınız, yani tüm yakalamaları gösterecek olsaydı, tamamen aynı görünecekti (cntd)
barlop

(cntd) Belki de yakalamaları gösterdiğini düşünüyorsunuz, ama göstermiyor, maçları gösteriyor
barlop

6

.Match () fonksiyonu str.match(regexp)aşağıdaki işlemleri gerçekleştirecektir

  • Orada eğer olduğunu bir eşleşme döndürür:
    • eğer gbayrağı olan regexp kullanılan: tüm alt dizeleri döndürür (yakalama grupları dikkate alınmaz)
    • eğer gbayrak edilir değil regexp kullanılan: Bu aynı dönecektirregexp.exec(str)
  • varsa hiçbir maç onu dönecektir:
    • null

Bayrağı kullanan .match () örnekleri g:

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

Ve .match () olmadan gbayrak eşdeğerdir .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 () fonksiyonu regexp.exec(str)aşağıdaki işlemleri gerçekleştirecektir

  • Orada eğer olduğunu bir eşleşme döndürür:
    • eğer gbayrağı olan regexp kullanılan: o dönecektir (denir, her zaman için) : [N_MatchedStr, N_Captured1, N_Captured2, ...]sonrakinin Nmaç. Önemli: regexp nesnesi bir değişkende depolanmamışsa (aynı nesne olması gerekir) sonraki eşleşmeye ilerlemeyecektir
    • eğer gbayrak edilir değil regexp kullanılan: bir varmış gibi aynı dönecektir gbayrağı ve sadece bir kez ilk kez ve için çağrıldı.
  • varsa hiçbir maç onu dönecektir:
    • null

.Exec () örneği ( gişaret kullanılarak depolanan normal ifade + = her çağrıda değişir):

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
}

Örnekleri arasında .exec () o olduğu değil her çağrı ile değiştirilmesi:

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

Bazen regex.exec () string.match () 'den çok daha fazla zaman alır .

String.match () ve regex.exec () 'in sonucu aynıysa (örn: \ g bayrağı kullanılmadığında), regex.exec () x2 ile x30 arasında bir yerde string sonra olacaktır. eşleşme():

Bu nedenle, bu gibi durumlarda, "new RegExp (). Exec ()" yaklaşımını kullanmak, yalnızca genel bir normal ifadeye ihtiyaç duyduğunuzda kullanılmalıdır (yani, birden çok kez çalıştırmak için).


1
Bir ölçütünüz var mı?
Sơn Trần-Nguyenn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.