apa perbedaan antara ?:, ?! dan? = dalam regex?

107

Saya mencari arti dari ungkapan-ungkapan ini tetapi tidak dapat memahami perbedaan yang tepat di antara mereka. Inilah yang mereka katakan:

  • ?: Cocokkan ekspresi tetapi jangan menangkapnya.
  • ?= Cocokkan sufiks tetapi kecualikan dari tangkapan.
  • ?! Cocok jika sufiks tidak ada.

Saya mencoba menggunakan ini dalam RegEx sederhana dan mendapatkan hasil yang serupa untuk semua. contoh: 3 ekspresi berikut memberikan hasil yang sangat mirip.

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*
RK Poddar
sumber
Tolong tunjukkan kasus uji Anda. Mereka seharusnya tidak memberikan hasil yang sama.
Bergi
@ sepp2k, hasilnya sama dalam beberapa kasus, salah satunya disebutkan dalam pertanyaan.
RK Poddar
@Bergi, saya mengujinya dengan data acak, berisi kata-kata bahasa Inggris, nomor telepon, url, alamat email, nomor, dll.
RK Poddar
4
@RKAgarwal Ah, saya melihat apa yang Anda lakukan di sana. Anda menambahkan *setelah grup, jadi mereka diabaikan begitu saja.
sepp2k
catatan noobie : Anda hanya akan menggunakan ini di awal tanda kurung, dan tanda kurung membentuk grup penangkap (kumpulan tanda kurung yang berbeda mengekstrak bagian teks yang berbeda).
Ryan Taylor

Jawaban:

152

Perbedaan antara ?=dan ?!adalah bahwa yang pertama membutuhkan ekspresi yang diberikan agar cocok dan yang terakhir membutuhkan ekspresi yang tidak cocok. Misalnya a(?=b)akan cocok dengan "a" di "ab", tapi bukan "a" di "ac". Padahal a(?!b)akan cocok dengan "a" di "ac", tapi bukan "a" di "ab".

Perbedaan antara ?:dan ?=is yang ?=mengecualikan ekspresi dari keseluruhan pertandingan sementara ?:tidak membuat grup penangkap. Jadi misalnya a(?:b)akan cocok dengan "ab" di "abc", sedangkan a(?=b)hanya akan cocok dengan "a" di "abc". a(b)akan cocok dengan "ab" di "abc" dan membuat gambar yang berisi "b".

sepp2k.dll
sumber
80
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

Silakan periksa di sini: http://www.regular-expressions.info/lookaround.html untuk tutorial yang sangat bagus dan contoh tentang lookahead dalam ekspresi reguler.

anubhava.dll
sumber
15
Namun JavaScript tidak tahu lookbehind.
Bergi
1
Yang ini lebih lengkap untuk regex umum.
Yan Yang
/ (? <= ^ a) b / bekerja untuk saya di javascript! Sepertinya tidak ada tutorial untuk mencari di belakang Javascript di internet.
Y. Yoshii
Hanya versi terbaru dari browser yang mulai mendukung tampilan belakang di JS
anubhava
- anubhava Saya tidak tahu alternatif apa pun untuk / (? <= ^ A) b / menggunakan ekspresi reguler murni. Mungkin saya bisa tetapi saya harus mengandalkan fungsi panggilan balik.
Y. Yoshii
21

Untuk lebih memahami, mari terapkan tiga ekspresi plus grup penangkap dan analisis setiap perilaku.

  • () grup penangkap - ekspresi reguler di dalam tanda kurung harus cocok dan kecocokan membuat grup penangkap
  • (?:) non capturing group - regex di dalam tanda kurung harus cocok tetapi tidak membuat grup penangkap
  • (?=) positif melihat ke depan - menegaskan bahwa ekspresi reguler harus dicocokkan
  • (?!) pandangan negatif ke depan - menegaskan bahwa tidak mungkin untuk mencocokkan ekspresi reguler

Mari mendaftar q(u)iuntuk berhenti . qcocok dengan q dan kelompok penangkap ucocok dengan u . Pertandingan di dalam grup penangkap diambil dan grup penangkap dibuat. Jadi mesin terus berlanjut i. Dan iakan cocok dengan saya . Upaya pertandingan terakhir ini berhasil. qui dicocokkan dan grup penangkap dengan u dibuat.

Mari mendaftar q(?:u)iuntuk berhenti . Sekali lagi, qcocokkan q dan grup yang tidak menangkap ucocok dengan u . Pertandingan dari grup non-penangkap diambil, tetapi grup penangkap tidak dibuat. Jadi mesin terus berlanjut i. Dan iakan cocok dengan saya . Upaya pertandingan terakhir ini berhasil. qui cocok

Mari mendaftar q(?=u)iuntuk berhenti . Lookahead itu positif dan diikuti oleh tanda lain. Sekali lagi, qcocokkan q dan ucocokkan dengan u . Sekali lagi, kecocokan dari lookahead harus dibuang, sehingga mesin mundur dari istring ke u . Lookahead itu berhasil, jadi mesinnya terus berjalan i. Tapi itidak bisa menandingi kamu . Jadi percobaan pertandingan ini gagal.

Mari mendaftar q(?=u)uuntuk berhenti . Lookahead itu positif dan diikuti oleh tanda lain. Sekali lagi, qcocokkan q dan ucocokkan dengan u . Kecocokan dari lookahead harus dibuang, sehingga mesin mundur dari ustring ke u . Lookahead itu berhasil, jadi mesinnya terus berjalan u. Dan uakan cocok denganmu . Jadi percobaan pertandingan ini berhasil. qu cocok

Mari mendaftar q(?!i)uuntuk berhenti . Bahkan dalam hal ini lookahead bernilai positif (karena itidak cocok) dan diikuti oleh token lain. Sekali lagi, qcocok dengan q dan itidak cocok dengan u . Kecocokan dari lookahead harus dibuang, sehingga mesin mundur dari ustring ke u . Lookahead itu berhasil, jadi mesinnya terus berjalan u. Dan uakan cocok denganmu . Jadi percobaan pertandingan ini berhasil. qu cocok

Jadi, kesimpulannya, perbedaan nyata antara grup lookahead dan non-capturing adalah jika Anda hanya ingin menguji keberadaan atau menguji dan menyimpan pertandingan. Menangkap grup itu mahal jadi gunakan dengan bijaksana.

freedev
sumber
> sehingga mesin mundur dari i dalam string ke u. Lookahead berhasil, jadi mesin terus berlanjut dengan i. Tapi saya tidak bisa menyamai Anda INI benar-benar membingungkan. Mengapa mundur jika ini lookahead ?
Hijau
1
@Green Hal penting untuk dipahami tentang lookahead dan konstruksi lookaround lainnya adalah bahwa meskipun mereka melalui gerakan untuk melihat apakah subekspresi mereka dapat cocok, mereka tidak benar-benar "mengkonsumsi" teks apa pun. Itu mungkin agak membingungkan
freedev
7

Coba cocokkan foobardengan ini:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

Regex pertama akan cocok dan akan mengembalikan "bar" sebagai submatch pertama - (?=b)cocok dengan 'b', tetapi tidak menggunakannya, membiarkannya di tanda kurung berikut.

Regex kedua TIDAK akan cocok, karena mengharapkan "foo" diikuti oleh sesuatu yang berbeda dari 'b'.

(?:...)memiliki efek yang persis sama seperti simple (...), tetapi tidak mengembalikan bagian tersebut sebagai submatch.

lanzz
sumber
0

Cara termudah untuk memahami pernyataan adalah dengan memperlakukannya sebagai perintah yang dimasukkan ke dalam ekspresi reguler. Saat mesin menjalankan pernyataan, mesin akan segera memeriksa kondisi yang dijelaskan oleh pernyataan tersebut. Jika hasilnya benar, lanjutkan menjalankan ekspresi reguler.

BlackGlory
sumber
0

Inilah perbedaan nyata:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

Jika Anda tidak peduli konten setelah "?:" Atau "? =", "?:" Dan "? =" Sama saja. Keduanya baik-baik saja untuk digunakan.

Tetapi jika Anda membutuhkan konten tersebut untuk proses lebih lanjut (tidak hanya mencocokkan semuanya. Dalam hal ini Anda cukup menggunakan "a (b)") Anda harus menggunakan "? =" Sebagai gantinya. Penyebab "?:" Akan melewatinya.

TeaDrinker
sumber