Apa perbedaan antara fungsi exec () RegExp dan fungsi String's match ()?

122

Jika saya menjalankan ini:

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

Saya mengerti ini:

["a", "a"]

Tetapi jika saya menjalankan ini:

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

Kemudian saya mendapatkan hasil yang diharapkan dari ini:

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

Apa bedanya?

Justin Warkentin
sumber
4
Anda mengulang execuntuk mendapatkan semua sub-pilihan.
zzzzBov
2
Perhatikan bahwa yang kedua +tidak diperlukan karena matchakan mengembalikan semua sub-ekspresi. .exechanya mengembalikan satu setiap kali, jadi tidak perlu itu +juga.
pimvdb
3
Selain itu, bilangan bertingkat seperti dua plus harus digunakan dengan sangat hati-hati karena mudah menyebabkan kemunduran yang dahsyat .
Marius Schulz
1
@MariusSchulz Terima kasih untuk tautannya. Itu menuntun saya untuk belajar tentang bilangan posesif dan pengelompokan atom. Hal yang sangat bagus untuk dipahami.
Justin Warkentin

Jawaban:

118

execdengan ekspresi reguler global dimaksudkan untuk digunakan dalam loop, karena masih akan mengambil semua subekspresi yang cocok. Begitu:

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 melakukan ini untuk Anda dan membuang grup yang ditangkap.

Ry-
sumber
39
Saya memiliki sesuatu untuk ditambahkan ke jawaban ini, seseorang tidak boleh menempatkan ekspresi reguler literal dalam kondisi while, seperti ini while(match = /[^\/]+/g.exec('/a/b/c/d')atau itu akan membuat pengulangan tak terbatas !. Seperti yang dinyatakan dengan jelas di MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
yeyo
7
@yeyo: Lebih khusus lagi, itu harus menjadi objek ekspresi reguler yang sama. Literal tidak mencapai itu.
Ry-
@ Ry- Saya pikir orang harus mencatat perilaku ini diperkenalkan di ES5. Sebelum ES5 new RegExp("pattern")dan /pattern/berarti hal yang berbeda.
Robert
75

Satu gambar lebih baik, Anda tahu ...

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

Lihat perbedaannya?

Catatan: Untuk menyorot, perhatikan bahwa grup yang diambil (misalnya: a, A) dikembalikan setelah pola yang cocok (misalnya: aA), ini bukan hanya pola yang cocok.

georg
sumber
28

/regex/.exec()mengembalikan hanya kecocokan pertama yang ditemukan, sementara "string".match()mengembalikan semuanya jika Anda menggunakan gflag di regex.

Lihat di sini: exec , match .

Alex Ciminian
sumber
23

Jika regex Anda bersifat global, dan Anda menangkapnya, Anda harus menggunakan exec. Pertandingan tidak akan mengembalikan semua tangkapan Anda.

Cocok bekerja sangat baik saat hanya mencocokkan (tidak menangkap). Anda menjalankannya sekali dan itu memberikan array dari semua pertandingan. (meskipun jika regex tidak global, maka pertandingan akan menunjukkan kecocokan diikuti dengan tangkapan)

Exec adalah apa yang Anda gunakan saat Anda menangkap, dan setiap kali dijalankan itu memberikan kecocokan, diikuti oleh tangkapan. (kecocokan akan berperilaku dengan cara memberikan kecocokan lengkap diikuti dengan tangkapan, hanya jika regex tidak global).

Penggunaan lain dengan Exec, mendapatkan indeks atau posisi, dari suatu kecocokan. Jika Anda memiliki variabel untuk regex Anda, Anda dapat menggunakan .lastIndex dan mendapatkan posisi yang cocok. Objek regex memiliki .lastIndex, dan objek regex adalah tempat Anda melakukan .exec. Pencocokan titik dilakukan pada sebuah string dan Anda tidak akan dapat melakukan objek regex dot lastIndex

Sebuah string, memiliki fungsi match, yang diberikan regex. Dan regex, memiliki fungsi exec, dan mengirimkan string

exec Anda menjalankan beberapa kali. pertandingan yang Anda jalankan sekali

Sebaiknya gunakan kecocokan saat tidak menangkap dan saat menangkap Anda bisa menggunakan exec yang lebih kuat karena bagus untuk menangkap, tetapi jika Anda memang menggunakan kecocokan saat menangkap, lihat bahwa itu menunjukkan penangkapan saat regex tidak global, tetapi tidak. t show menangkap saat regex bersifat global.

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

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

Hal lainnya adalah jika Anda menggunakan exec, catatan yang dipanggil di regex, maka jika Anda menggunakan variabel untuk regex, Anda memiliki lebih banyak kekuatan.

Anda tidak mendapatkan kecocokan saat Anda tidak menggunakan variabel untuk regex, jadi gunakan variabel untuk regex, saat menggunakan 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
>

Dan dengan exec, Anda bisa mendapatkan "indeks" dari pertandingan tersebut

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

Jadi, jika Anda ingin mengindeks atau menangkap, maka gunakan exec (ingatlah bahwa seperti yang Anda lihat, dengan "indeks", "indeks" yang diberikannya benar-benar kejadian ke-n, dihitung dari 1. Jadi Anda bisa mendapatkan yang tepat indeks dengan mengurangi 1. Dan seperti yang Anda lihat, ini memberikan 0 - Indeks terakhir 0 - untuk tidak ditemukan).

Dan jika Anda ingin merentangkan pencocokan, Anda dapat menggunakannya saat menangkap, tetapi tidak saat regex bersifat global, dan saat Anda melakukannya untuk itu, maka konten larik tidak semuanya cocok, tetapi penuh. pertandingan diikuti dengan penangkapan.

barlop
sumber
Ya, memahami cara kerja r.lastIndexadalah faktor kunci untuk memahami perbedaan antara execdan match.
runun
@barlop "Pertandingan tidak akan cocok dengan semua tangkapan", serius? "a, b, c, aa, bb, cc" .match (/ (\ w +) / g) => ["a", "b", "c", "aa", "bb", "cc" ]. Bagaimana menjelaskan bahwa itu menyimpan semuanya?
MrHIDEn
@barlop If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.Saya mendapatkannya di konsol. Cukup salin / tempel "a,b,c,aa,bb,cc".match(/(\w+)/g);Opera, Firefox.
MrHIDEn
@MrHIDEn Saya tidak akan menggunakan bahasa yang Anda gunakan dalam kutipan yang salah. Dan yang penting adalah apa yang ditampilkan dan apa yang dapat kita lihat .. apakah ada cache di belakang layar juga tidak relevan. Dan sudah lama sejak saya melihat ini, tetapi tidak menunjukkan semua tangkapan .. Bahkan jika Anda melakukan contoh Anda "a,b,c,aa,bb,cc".match(/(\w+)/g) Apa yang terjadi di sana itu menunjukkan semua pertandingan, dan kebetulan Anda menangkap setiap pertandingan, jadi jika itu menunjukkan semua tangkapan, itu akan terlihat persis sama (cntd)
barlop
(cntd) Jadi mungkin Anda berpikir itu menunjukkan tangkapan, tetapi ternyata tidak, itu menunjukkan pertandingan
barlop
6

The .match () fungsi str.match(regexp)akan melakukan hal berikut:

  • jika ada adalah pertandingan itu akan kembali:
    • jika gbendera yang digunakan di regexp: itu akan mengembalikan semua substring (mengabaikan kelompok capture)
    • jika gflag tidak digunakan di regexp: ini akan mengembalikan sama sepertiregexp.exec(str)
  • jika tidak ada yang cocok maka akan dikembalikan:
    • null

Contoh .match () yang menggunakan 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

Dan .match () tanpa gflag sama dengan .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

The .exec () fungsi regexp.exec(str)akan melakukan hal berikut:

  • jika ada adalah pertandingan itu akan kembali:
    • jika gbendera yang digunakan di regexp: itu akan kembali (untuk setiap kali hal itu disebut) : [N_MatchedStr, N_Captured1, N_Captured2, ...]dari berikutnya Npertandingan. Penting: itu tidak akan maju ke kecocokan berikutnya jika objek regexp tidak disimpan dalam variabel (harus objek yang sama)
    • jika gflag tidak digunakan dalam regexp: ia akan mengembalikan sama seperti jika gflag memiliki flag dan dipanggil untuk pertama kali dan hanya sekali.
  • jika tidak ada yang cocok maka akan dikembalikan:
    • null

Contoh .exec () (regexp + disimpan menggunakan gflag = itu berubah dengan setiap panggilan):

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
}

Contoh .exec () ketika tidak berubah dengan setiap panggilan:

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"]
ajax333221
sumber
1

Terkadang regex.exec () membutuhkan lebih banyak waktu dibandingkan string.match ().

Perlu disebutkan bahwa jika hasil dari string.match () dan regex.exec () sama (contoh: saat tidak menggunakan \ g flag), regex.exec () akan mengambil tempat antara x2 hingga x30 lalu string. pertandingan():

Oleh karena itu, dalam kasus seperti itu, menggunakan pendekatan "new RegExp (). Exec ()" harus digunakan hanya saat Anda membutuhkan regex global (yaitu untuk mengeksekusi lebih dari sekali).

Dorony
sumber
1
Apakah Anda punya patokan?
Sơn Trần-Nguyễn