Bagaimana non-menangkap kelompok, yaitu (?:)
, digunakan dalam ekspresi reguler dan apa yang mereka baik untuk?
Biarkan saya mencoba untuk menjelaskan hal ini dengan sebuah contoh.
Perhatikan teks berikut:
http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex
Sekarang, jika saya menerapkan regex di bawah ini di atasnya...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
... Saya akan mendapatkan hasil sebagai berikut:
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "https://stackoverflow.com/questions/tagged/regex"
Group 1: "https"
Group 2: "stackoverflow.com"
Group 3: "/questions/tagged/regex"
Tapi aku don't peduli tentang protokol-aku hanya ingin host dan jalur dari URL. Jadi, saya mengubah regex untuk mencakup non-menangkap kelompok (?:)
.
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
Sekarang, saya hasilnya terlihat seperti ini:
Match "http://stackoverflow.com/"
Group 1: "stackoverflow.com"
Group 2: "/"
Match "https://stackoverflow.com/questions/tagged/regex"
Group 1: "stackoverflow.com"
Group 2: "/questions/tagged/regex"
Lihat? Kelompok pertama belum ditangkap. Parser menggunakannya untuk mencocokkan teks, tetapi mengabaikan hal itu kemudian, dalam hasil akhir.
Seperti yang diminta, biarkan saya mencoba untuk menjelaskan kelompok juga.
Nah, kelompok-kelompok yang melayani berbagai tujuan. Mereka dapat membantu anda untuk mengekstrak informasi yang tepat dari sebuah pertandingan besar (yang juga dapat dinamakan), mereka membiarkan anda bertanding sebelumnya dicocokkan kelompok, dan dapat digunakan untuk substitusi. Let's mencoba beberapa contoh, akan kita?
Ok, bayangkan anda memiliki beberapa jenis XML atau HTML (diketahui bahwa regex mungkin tidak menjadi alat terbaik untuk pekerjaan itu, tapi itu bagus sebagai contoh). Anda ingin mengurai kategori, sehingga anda bisa melakukan sesuatu seperti ini (saya telah menambahkan spasi untuk membuatnya lebih mudah untuk memahami):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\1\>
Pertama regex memiliki nama group (TAG), sedangkan yang kedua menggunakan grup umum. Kedua regexes melakukan hal yang sama: mereka menggunakan nilai dari kelompok pertama (nama tag) untuk mencocokkan tag penutup. Perbedaannya adalah bahwa yang pertama menggunakan nama untuk mencocokkan nilai, dan yang kedua menggunakan indeks kelompok (yang dimulai pada 1).
Let's mencoba beberapa substitusi sekarang. Perhatikan teks berikut:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
Sekarang, let's menggunakan bodoh ini regex di atas itu:
\b(\S)(\S)(\S)(\S*)\b
Ini regex yang cocok dengan kata-kata dengan minimal 3 karakter, dan menggunakan kelompok-kelompok untuk memisahkan tiga huruf pertama. Hasilnya adalah ini:
Match "Lorem"
Group 1: "L"
Group 2: "o"
Group 3: "r"
Group 4: "em"
Match "ipsum"
Group 1: "i"
Group 2: "p"
Group 3: "s"
Group 4: "um"
...
Match "consectetuer"
Group 1: "c"
Group 2: "o"
Group 3: "n"
Group 4: "sectetuer"
...
Jadi, jika kita menerapkan substitusi string:
$1_$3$2_$4
... lebih dari itu, kami mencoba untuk menggunakan kelompok pertama, menambah garis bawah, gunakan ketiga kelompok, kemudian kelompok kedua, menambah garis bawah, dan kemudian keempat kelompok. String yang dihasilkan akan menjadi seperti berikut.
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.
Anda dapat menggunakan nama kelompok untuk substitusi juga menggunakan ${nama}
.
Untuk bermain-main dengan regexes, saya sarankan http://regex101.com/, yang menawarkan baik jumlah rincian tentang bagaimana regex bekerja; hal ini juga menawarkan beberapa regex mesin untuk memilih dari.
Anda dapat menggunakan menangkap kelompok untuk mengatur dan mengurai sebuah ekspresi. Non-menangkap kelompok memiliki manfaat pertama, tapi doesn't memiliki overhead yang kedua. Anda masih dapat mengatakan non-menangkap kelompok adalah opsional, misalnya.
Katakanlah anda ingin mencocokkan numerik teks, tapi beberapa angka yang bisa ditulis sebagai 1, 2, 3, 4,... Jika anda ingin menangkap bagian numerik, tetapi tidak (opsional) akhiran anda dapat menggunakan non-menangkap kelompok.
([0-9]+)(?:st|nd|rd|th)?
Yang akan cocok dengan angka-angka dalam bentuk 1, 2, 3,... atau dalam bentuk 1, 2, 3,... tapi itu hanya akan menangkap bagian numerik.
?:
ini digunakan ketika anda ingin grup ekspresi, tetapi anda tidak ingin menyimpannya sebagai cocok/ditangkap bagian dari string.
Sebuah contoh akan menjadi sesuatu untuk mencocokkan alamat IP:
/(?:\d{1,3}\.){3}\d{1,3}/
Perhatikan bahwa saya don't peduli tentang penghematan pertama 3 oktet, tapi (?:...)
pengelompokan memungkinkan saya untuk mempersingkat ekspresi reguler tanpa menimbulkan overhead menangkap dan menyimpan satu pertandingan.
Hal ini membuat kelompok non-menangkap, yang berarti bahwa substring ditandingi oleh kelompok yang tidak akan termasuk dalam daftar menangkap. Contoh di ruby untuk menggambarkan perbedaan:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
SEJARAH MOTIVASI: keberadaan non-menangkap kelompok dapat dijelaskan dengan menggunakan tanda kurung. Mempertimbangkan ekspresi (a|b)c dan a|bc, karena prioritas dari rangkaian lebih dari |, ekspresi ini mewakili dua bahasa yang berbeda ({ac, bc} dan {a, bc} masing-masing). Namun, tanda kurung juga digunakan sebagai pencocokan kelompok (seperti yang dijelaskan oleh jawaban yang lain...).
Bila anda ingin memiliki kurung tapi tidak menangkap subexpressionn anda menggunakan NON-MENANGKAP KELOMPOK. Dalam contoh, (?:a|b)c
Kelompok-kelompok yang ambil anda dapat menggunakan kemudian di regex untuk mencocokkan ATAU anda dapat menggunakan mereka dalam penggantian bagian dari regex. Membuat non-menangkap kelompok hanya membebaskan kelompok yang digunakan untuk salah satu dari alasan-alasan ini.
Non-menangkap kelompok-kelompok yang besar jika anda mencoba untuk menangkap banyak hal yang berbeda dan ada beberapa kelompok anda don't ingin menangkap.
Thats cukup banyak alasan mengapa mereka ada. Saat anda belajar tentang kelompok, belajar tentang Kelompok Atom, mereka melakukan banyak hal! Ada juga lookaround kelompok tetapi mereka yang sedikit lebih kompleks dan tidak digunakan begitu banyak.
Contoh penggunaan di kemudian hari dalam regex (backreference):
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>
[ Menemukan sebuah tag xml (tanpa ns dukungan) ]
([A-Z][A-Z0-9]*)
adalah menangkap kelompok (dalam hal ini adalah tagname)
Kemudian di regex adalah \1
yang berarti itu hanya akan cocok dengan teks yang sama yang berada dalam kelompok pertama (yang ([A-Z][A-Z0-9]*)
grup) (dalam hal ini adalah pencocokan tag akhir).
Biarkan saya mencoba hal ini dengan sebuah contoh :-
Regex Kode :- (?:hewan)(?:=)(\w+)(,)\1\2
Pencarian String :-
Baris 1 - hewan=kucing,anjing,kucing,harimau,anjing
Garis 2 - hewan=kucing,kucing,anjing,anjing,harimau
Garis 3 - hewan=anjing,anjing,kucing,kucing,harimau
(?:hewan)
--> Non-Ditangkap Kelompok 1
(?:=)
--> Non-Ditangkap Kelompok 2
(\w+)
--> Ditangkap Kelompok 1
(,)
--> Ditangkap Kelompok 2
\1
--> hasil yang ditangkap kelompok 1 saya.e Di Baris 1 adalah kucing,Di Baris 2 adalah kucing,Di Baris ke-3 adalah anjing.
\2
-->hasil yang ditangkap kelompok 2 saya.e koma(,)
Jadi dalam kode ini dengan memberikan \1 \2 kita mengingat atau mengulang hasil yang ditangkap kelompok 1 dan 2 masing-masing kemudian di kode.
Sesuai urutan kode (?:hewan) harus menjadi kelompok 1 dan (?:=) harus kelompok 2 dan terus..
tapi dengan memberikan ?: kami membuat pertandingan-kelompok non ditangkap(yang tidak menghitung di dicocokkan kelompok, sehingga pengelompokan nomor mulai dari yang pertama ditangkap kelompok dan bukan non ditangkap), sehingga pengulangan hasil pertandingan group (?:hewan) dapat't akan dipanggil nanti pada kode.
Harapan ini menjelaskan penggunaan non menangkap kelompok.
Nah saya JavaScript pengembang dan akan mencoba untuk menjelaskan maknanya yang berkaitan dengan JavaScript.
Pertimbangkan skenario di mana anda ingin mencocokkan kucing adalah hewan
ketika anda ingin mencocokkan kucing dan hewan dan keduanya harus memiliki lebih
di antara mereka.
// this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]
// using lookahead pattern it will match only "cat" we can
// use lookahead but the problem is we can not give anything
// at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]
//so I gave another grouping parenthesis for animal
// in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]
// we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
Di kompleks ekspresi reguler anda mungkin memiliki situasi muncul di mana anda ingin menggunakan sejumlah besar kelompok-kelompok yang ada untuk pengulangan yang cocok dan yang tidak untuk memberikan kembali referensi. Secara default teks pencocokan masing-masing group dimuat ke dalam backreference array. Di mana kami memiliki banyak kelompok dan hanya perlu untuk dapat referensi beberapa dari mereka dari backreference array kita dapat mengganti perilaku default ini untuk memberitahu ekspresi reguler yang kelompok-kelompok tertentu yang ada hanya untuk pengulangan penanganan dan tidak perlu ditangkap dan disimpan dalam backreference array.
Saya tidak bisa mengomentari atas jawaban untuk mengatakan ini: saya ingin menambahkan eksplisit titik yang hanya tersirat dalam jawaban atas:
Non-menangkap kelompok (?...)
tidak tidak menghapus setiap karakter asli dari pertandingan penuh, hanya reorganises regex visual programmer.
Untuk mengakses bagian tertentu dari regex tanpa didefinisikan asing karakter anda akan selalu perlu untuk menggunakan .kelompok(<index>)
tl;dr non-menangkap kelompok-kelompok, seperti namanya ini adalah bagian dari ekspresi reguler yang tidak anda inginkan untuk dimasukkan ke dalam pertandingan dan ?:
adalah suatu cara untuk mendefinisikan kelompok sebagai non-menangkap.
Let's mengatakan anda memiliki alamat email [email protected]
. Berikut regex akan membuat dua kelompok, id dan @example.com bagian. (\p{Alpha}*[a-z])(@example.com)
. Untuk kesederhanaan's sake, kami mengeluarkan seluruh nama domain termasuk karakter@
.
Sekarang mari's mengatakan, anda hanya perlu id bagian dari alamat. Apa yang anda ingin lakukan adalah untuk mengambil kelompok pertama dari hasil pertandingan, dikelilingi oleh ()
dalam regex dan cara untuk melakukan ini adalah dengan menggunakan non-menangkap kelompok sintaks, yaitu ?:
. Jadi regex (\p{Alpha}*[a-z])(?:@example.com)
akan kembali hanya id bagian dari email.
Satu hal yang menarik bahwa saya datang di ini adalah kenyataan bahwa anda dapat menangkap kelompok dalam non-menangkap kelompok. Silahkan lihat di bawah ini regex untuk pencocokan url web:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
Input string url:
var url = "http://www.ora.com:80/goodparts?q#fragment";
Kelompok pertama di regex (?:([A-Za-z]+):)
adalah non-menangkap kelompok yang sesuai dengan skema protokol dan usus besar :
karakter yaitu http:
tapi ketika saya menjalankan kode di bawah ini, saya melihat 1 indeks kembali array yang berisi string http
ketika aku berpikir bahwa http
dan dua :
kedua tidak akan mendapatkan diberitakan saat mereka berada di dalam kamar non-menangkap kelompok.
console.debug(parse_url_regex.exec(url));
Saya pikir jika kelompok pertama (?:([A-Za-z]+):)
adalah non-menangkap kelompok maka mengapa hal ini kembali http
string dalam array output.
Jadi jika anda melihat bahwa ada bersarang group ([A-Za-z]+)
dalam non-menangkap kelompok. Yang bersarang group ([A-Za-z]+)
adalah menangkap kelompok (tidak memiliki ?:
di awal) itu sendiri di dalam kamar non-menangkap kelompok (?:([A-Za-z]+):)
. Yang's mengapa teks http
masih akan ditangkap tapi dua :
karakter yang ada di dalam non-menangkap kelompok tetapi di luar menangkap kelompok doesn't mendapatkan dilaporkan pada keluaran array.
Saya pikir saya akan memberikan anda jawabannya, Don't menggunakan capture variabel tanpa memeriksa bahwa pertandingan berhasil.
Penangkapan variabel, $1, dll, adalah tidak sah kecuali pertandingan berhasil, dan mereka're tidak dibersihkan, baik.
#!/usr/bin/perl
use warnings;
use strict;
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
print "Fred wants a $1";
}
else
{
print "Fred dont wants a $1 $2";
}
Dalam contoh di atas, Untuk menghindari menangkap bronto di $1, (?:) digunakan. Jika pola ini cocok , maka $1 ditangkap saat berikutnya dikelompokkan pola. Jadi, output akan menjadi seperti di bawah ini:
Fred wants a burger
Hal ini Berguna jika anda don't ingin pertandingan yang akan disimpan .
Buka Google Chrome devTools dan kemudian Konsol tab dan ketik ini:
"Peace".match(/(\w)(\w)(\w)/)
Jalankan dan anda akan melihat:
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
The JavaScript
RegExp mesin menangkap tiga kelompok, item dengan indeks 1,2,3. Sekarang menggunakan non-menangkap tanda untuk melihat hasilnya.
"Peace".match(/(?:\w)(\w)(\w)/)
Hasilnya adalah:
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
Ini jelas apa yang non menangkap kelompok.
Yang sangat sederhana, Kita dapat memahami dengan sederhana upload contoh, misalkan jika tanggal yang disebutkan sebagai 1 januari 2019 atau 2 Mei 2019 atau tanggal lain dan kita hanya ingin mengubahnya ke dd/mm/yyyy format kita tidak perlu bulan's nama yang bulan januari atau februari untuk hal ini, sehingga dalam rangka untuk menangkap bagian numerik, tetapi tidak (opsional) akhiran anda dapat menggunakan non-menangkap kelompok.
jadi ekspresi reguler akan,
([0-9]+)(?:January|February)?
Yang sederhana seperti itu.