Bagaimana kelompok yang tidak menangkap, yaitu (?:)
, digunakan dalam ekspresi reguler dan untuk apa mereka?
Bagaimana kelompok yang tidak menangkap, yaitu (?:)
, digunakan dalam ekspresi reguler dan untuk apa mereka?
Jawaban:
Biarkan saya mencoba menjelaskan ini dengan sebuah contoh.
Pertimbangkan teks berikut:
http://stackoverflow.com/
/programming/tagged/regex
Sekarang, jika saya menerapkan regex di bawah ini ...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
... Saya akan mendapatkan hasil berikut:
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "/programming/tagged/regex"
Group 1: "https"
Group 2: "stackoverflow.com"
Group 3: "/questions/tagged/regex"
Tapi saya tidak peduli dengan protokol - saya hanya ingin host dan path dari URL. Jadi, saya mengubah regex untuk memasukkan grup yang tidak menangkap (?:)
.
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
Sekarang, hasil saya terlihat seperti ini:
Match "http://stackoverflow.com/"
Group 1: "stackoverflow.com"
Group 2: "/"
Match "/programming/tagged/regex"
Group 1: "stackoverflow.com"
Group 2: "/questions/tagged/regex"
Lihat? Grup pertama belum ditangkap. Parser menggunakannya untuk mencocokkan teks, tetapi mengabaikannya nanti, pada hasil akhir.
Seperti yang diminta, izinkan saya mencoba menjelaskan kelompok juga.
Ya, kelompok melayani banyak tujuan. Mereka dapat membantu Anda untuk mengekstrak informasi yang tepat dari kecocokan yang lebih besar (yang juga bisa disebut), mereka memungkinkan Anda membuat ulang grup yang cocok sebelumnya, dan dapat digunakan untuk pergantian pemain. Mari kita coba beberapa contoh, oke?
Bayangkan Anda memiliki semacam XML atau HTML (perlu diketahui bahwa regex mungkin bukan alat terbaik untuk pekerjaan itu , tetapi itu bagus sebagai contoh). Anda ingin mengurai tag, sehingga Anda dapat melakukan sesuatu seperti ini (saya telah menambahkan spasi untuk membuatnya lebih mudah dimengerti):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\1\>
Regex pertama memiliki grup bernama (TAG), sedangkan regex kedua menggunakan grup umum. Kedua regex melakukan hal yang sama: mereka menggunakan nilai dari grup pertama (nama tag) untuk mencocokkan tag penutup. Perbedaannya adalah bahwa yang pertama menggunakan nama untuk mencocokkan nilai, dan yang kedua menggunakan indeks grup (yang dimulai pada 1).
Mari kita coba beberapa pergantian sekarang. Pertimbangkan teks berikut:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
Sekarang, mari kita gunakan regex bodoh ini di atasnya:
\b(\S)(\S)(\S)(\S*)\b
Regex ini cocok dengan kata-kata dengan setidaknya 3 karakter, dan menggunakan grup 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 string substitusi:
$1_$3$2_$4
... di atasnya, kami mencoba menggunakan grup pertama, tambahkan garis bawah, gunakan grup ketiga, lalu grup kedua, tambahkan garis bawah lain, dan kemudian grup keempat. String yang dihasilkan akan seperti yang di bawah ini.
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 juga dapat menggunakan grup yang disebut sebagai pengganti, menggunakan ${name}
.
Untuk bermain-main dengan regex , saya sarankan http://regex101.com/ , yang menawarkan sejumlah detail tentang cara kerja regex; itu juga menawarkan beberapa mesin regex untuk dipilih.
Anda dapat menggunakan menangkap grup untuk mengatur dan mengurai ekspresi. Grup yang tidak menangkap memiliki manfaat pertama, tetapi tidak memiliki overhead yang kedua. Anda masih dapat mengatakan bahwa grup yang tidak menangkap adalah opsional, misalnya.
Katakanlah Anda ingin mencocokkan teks numerik, tetapi beberapa angka dapat ditulis sebagai 1, 2, 3, 4, ... Jika Anda ingin mengambil bagian numerik, tetapi bukan sufiks (opsional), Anda dapat menggunakan grup yang tidak menangkap .
([0-9]+)(?:st|nd|rd|th)?
Itu akan cocok dengan angka dalam formulir 1, 2, 3 ... atau dalam bentuk 1, 2, 3, ... tetapi itu hanya akan menangkap bagian numerik.
?:
digunakan ketika Anda ingin mengelompokkan ekspresi, tetapi Anda tidak ingin menyimpannya sebagai bagian string yang cocok / ditangkap.
Contohnya adalah sesuatu yang cocok dengan alamat IP:
/(?:\d{1,3}\.){3}\d{1,3}/
Perhatikan bahwa saya tidak peduli tentang menyimpan 3 oktet pertama, tetapi (?:...)
pengelompokan memungkinkan saya untuk mempersingkat regex tanpa mengeluarkan biaya tambahan untuk menangkap dan menyimpan korek api.
Itu membuat grup tidak menangkap, yang berarti bahwa substring yang cocok dengan grup itu tidak akan dimasukkan dalam daftar tangkapan. Contoh dalam ruby untuk menggambarkan perbedaan:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
(?:)
tidak menghasilkan tangkapan, bukan untuk menunjukkan contoh yang bermanfaat (?:)
. (?:)
berguna ketika Anda ingin mengelompokkan sub-ekspresi (misalnya ketika Anda ingin menerapkan quantifiers ke sub-ekspresi non-atom atau jika Anda ingin membatasi ruang lingkup a |
), tetapi Anda tidak ingin menangkap apa pun.
MOTIVASI SEJARAH:
Keberadaan kelompok yang tidak menangkap dapat dijelaskan dengan menggunakan tanda kurung.
Pertimbangkan ungkapan-ungkapan (a|b)c
dan a|bc
, karena prioritas rangkaian diakhiri |
, ungkapan-ungkapan ini mewakili dua bahasa yang berbeda ( {ac, bc}
dan {a, bc}
masing - masing).
Namun, tanda kurung juga digunakan sebagai kelompok yang cocok (seperti yang dijelaskan oleh jawaban lain ...).
Ketika Anda ingin memiliki tanda kurung tetapi tidak menangkap sub-ekspresi Anda menggunakan KELOMPOK NON-CAPTURING. Dalam contoh,(?:a|b)c
Biarkan saya coba ini dengan sebuah contoh:
Kode Regex: (?:animal)(?:=)(\w+)(,)\1\2
Cari String:
Baris 1 - animal=cat,dog,cat,tiger,dog
Baris 2 - animal=cat,cat,dog,dog,tiger
Baris 3 - animal=dog,dog,cat,cat,tiger
(?:animal)
-> Grup Non-Tertangkap 1
(?:=)
-> Grup Non-Tertangkap 2
(\w+)
-> Grup Yang Ditangkap 1
(,)
-> Grup Yang Ditangkap 2
\1
-> hasil tangkapan kelompok 1 yaitu Jalur 1 adalah kucing, Baris 2 adalah kucing, Baris 3 adalah anjing.
\2
-> hasil tangkapan kelompok 2 yaitu koma (,)
Jadi dalam kode ini dengan memberi \1
dan \2
kami mengingat atau mengulangi hasil dari kelompok yang ditangkap 1 dan 2 masing-masing kemudian dalam kode.
Sesuai urutan kode (?:animal)
harus grup 1 dan (?:=)
harus grup 2 dan berlanjut ..
tetapi dengan memberikan ?:
kami membuat kelompok pertandingan tidak ditangkap (yang tidak dihitung dalam kelompok cocok, sehingga nomor pengelompokan dimulai dari kelompok yang ditangkap pertama kali dan bukan yang ditangkap), sehingga pengulangan hasil dari kelompok pertandingan (?:animal)
tidak dapat dipanggil nanti dalam kode.
Semoga ini menjelaskan penggunaan kelompok yang tidak menangkap.
Grup yang menangkap Anda dapat menggunakan nanti di regex untuk mencocokkan ATAU Anda dapat menggunakannya di bagian pengganti regex. Membuat grup yang tidak menangkap cukup mengecualikan grup tersebut dari penggunaan karena salah satu dari alasan ini.
Grup yang tidak menangkap sangat bagus jika Anda mencoba untuk menangkap banyak hal yang berbeda dan ada beberapa kelompok yang tidak ingin Anda tangkap.
Itulah alasan mengapa mereka ada. Saat Anda belajar tentang grup, belajar tentang Grup Atom , mereka melakukan banyak hal! Ada juga kelompok lookaround tetapi mereka sedikit lebih kompleks dan tidak banyak digunakan.
Contoh penggunaan nanti dalam regex (backreference):
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>
[Menemukan tag xml (tanpa dukungan ns)]
([A-Z][A-Z0-9]*)
adalah grup penangkap (dalam hal ini adalah tagname)
Kemudian dalam regex adalah \1
yang berarti hanya akan cocok dengan teks yang sama yang ada di grup pertama ( ([A-Z][A-Z0-9]*)
grup) (dalam hal ini cocok dengan tag akhir).
Yah saya adalah pengembang JavaScript dan akan mencoba menjelaskan maknanya yang berkaitan dengan JavaScript.
Pertimbangkan skenario di mana Anda ingin mencocokkan cat is animal
ketika Anda ingin mencocokkan kucing dan hewan dan keduanya harus ada is
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"]
Dalam ekspresi reguler yang kompleks, Anda mungkin memiliki situasi timbul di mana Anda ingin menggunakan sejumlah besar kelompok beberapa di antaranya ada untuk pencocokan pengulangan dan beberapa di antaranya ada untuk memberikan referensi kembali. Secara default, teks yang cocok dengan setiap grup dimuat ke dalam array referensi-balik. Di mana kami memiliki banyak grup dan hanya perlu dapat merujuk beberapa dari mereka dari array backreference, kami dapat mengganti perilaku default ini untuk memberi tahu ekspresi reguler bahwa grup tertentu hanya ada untuk penanganan pengulangan dan tidak perlu ditangkap dan disimpan dalam array backreference.
Saya tidak dapat mengomentari jawaban teratas untuk mengatakan ini: Saya ingin menambahkan titik eksplisit yang hanya tersirat dalam jawaban teratas:
Kelompok non-menangkap (?...)
tidak tidak menghapus karakter apapun dari pertandingan penuh asli, hanya mereorganisasi regex visual untuk programmer.
Untuk mengakses bagian tertentu dari regex tanpa karakter asing yang ditentukan, Anda harus selalu menggunakannya .group(<index>)
tl; dr grup yang tidak menangkap, seperti namanya adalah bagian dari regex yang tidak ingin Anda sertakan dalam pertandingan dan ?:
merupakan cara untuk mendefinisikan grup sebagai tidak menangkap.
Katakanlah Anda memiliki alamat email example@example.com
. Regex berikut akan membuat dua grup , bagian id dan bagian @ example.com. (\p{Alpha}*[a-z])(@example.com)
. Demi kesederhanaan, kami mengekstraksi seluruh nama domain termasuk @
karakter.
Sekarang katakanlah, Anda hanya perlu bagian id dari alamat. Yang ingin Anda lakukan adalah mengambil grup pertama dari hasil pertandingan, dikelilingi oleh ()
dalam regex dan cara untuk melakukannya adalah dengan menggunakan sintaks grup non-capturing, yaitu ?:
. Jadi regex (\p{Alpha}*[a-z])(?:@example.com)
akan mengembalikan hanya bagian id dari email.
Satu hal menarik yang saya temui adalah kenyataan bahwa Anda dapat memiliki grup menangkap di dalam grup yang tidak menangkap. Lihat di bawah ini regex untuk mencocokkan url web:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
Masukkan url string:
var url = "http://www.ora.com:80/goodparts?q#fragment";
Grup pertama di regex saya (?:([A-Za-z]+):)
adalah grup non-menangkap yang cocok dengan skema protokol dan :
karakter titik dua yaitu http:
tetapi ketika saya menjalankan kode di bawah, saya melihat indeks pertama dari array yang dikembalikan berisi string http
ketika saya memikirkan itu http
dan titik dua :
keduanya tidak akan dilaporkan karena mereka berada di dalam kelompok yang tidak menangkap.
console.debug(parse_url_regex.exec(url));
Saya pikir jika grup pertama (?:([A-Za-z]+):)
adalah grup yang tidak menangkap maka mengapa ia mengembalikan http
string dalam array output.
Jadi, jika Anda perhatikan ada grup bersarang ([A-Za-z]+)
di dalam grup yang tidak menangkap. Grup bersarang itu ([A-Za-z]+)
adalah grup yang menangkap (tidak memiliki ?:
di awal) di dalam dirinya sendiri di dalam grup yang tidak menangkap (?:([A-Za-z]+):)
. Itu sebabnya teks http
masih dapat ditangkap tetapi :
karakter titik dua yang ada di dalam grup yang tidak menangkap tetapi di luar grup yang menangkap tidak dilaporkan dalam larik keluaran.
Buka devTools Google Chrome Anda dan kemudian tab Console: dan ketik ini:
"Peace".match(/(\w)(\w)(\w)/)
Jalankan dan Anda akan melihat:
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
Mesin JavaScript
RegExp menangkap tiga grup, item dengan indeks 1,2,3. Sekarang gunakan tanda yang tidak menangkap untuk melihat hasilnya.
"Peace".match(/(?:\w)(\w)(\w)/)
Hasilnya adalah:
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
Ini jelas apa yang dimaksud dengan kelompok tidak menangkap.
Saya pikir saya akan memberi Anda jawabannya. Jangan gunakan variabel penangkapan tanpa memeriksa apakah pertandingan berhasil.
Variabel capture $1
,, dll, tidak valid kecuali jika pertandingan berhasil, dan mereka juga tidak dihapus.
#!/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 penangkapan bronto $1
, (?:)
digunakan.
Jika polanya cocok, maka $1
ditangkap sebagai pola yang dikelompokkan berikutnya.
Jadi, hasilnya akan seperti di bawah ini:
Fred wants a burger
Ini berguna jika Anda tidak ingin korek api disimpan.
Ini sangat sederhana, Kita dapat mengerti dengan contoh tanggal sederhana, misalkan jika tanggal tersebut disebutkan sebagai 1 Januari 2019 atau 2 Mei 2019 atau tanggal lainnya dan kami hanya ingin mengubahnya menjadi format dd / mm / yyyy kita tidak memerlukan bulan nama yang Januari atau Februari dalam hal ini, jadi untuk menangkap bagian numerik, tetapi bukan sufiks (opsional) Anda dapat menggunakan grup yang tidak menangkap.
jadi ekspresi regulernya adalah,
([0-9]+)(?:January|February)?
Sesederhana itu.