Belajar Ekspresi Reguler [ditutup]

166

Saya tidak begitu mengerti ekspresi reguler. Bisakah Anda menjelaskannya kepada saya dengan cara yang mudah diikuti? Jika ada alat atau buku online, dapatkah Anda juga menautkannya?

Teifion
sumber

Jawaban:

789

Bagian terpenting adalah konsep. Setelah Anda memahami bagaimana blok bangunan bekerja, perbedaan dalam jumlah sintaksis sedikit lebih dari dialek ringan. Lapisan di atas sintaks mesin ekspresi reguler Anda adalah sintaks dari bahasa pemrograman yang Anda gunakan. Bahasa seperti Perl menghapus sebagian besar komplikasi ini, tetapi Anda harus mengingat pertimbangan lain jika Anda menggunakan ekspresi reguler dalam program C.

Jika Anda menganggap ekspresi reguler sebagai blok bangunan yang dapat Anda campur dan padankan sesuka Anda, ada baiknya Anda belajar cara menulis dan men-debug pola Anda sendiri, tetapi juga bagaimana memahami pola yang ditulis oleh orang lain.

Mulai dari yang sederhana

Secara konseptual, ekspresi reguler paling sederhana adalah karakter literal. Polanya Ncocok dengan karakter 'N'.

Ekspresi reguler di sebelah urutan pertandingan yang sama. Misalnya, polanya Nickcocok dengan urutan 'N' diikuti oleh 'i' diikuti oleh 'c' diikuti oleh 'k'.

Jika Anda pernah menggunakan grepUnix — sekalipun hanya untuk mencari string yang tampak biasa — Anda telah menggunakan ekspresi reguler! (The redalam grepmengacu pada ekspresi reguler.)

Pesan dari menu

Menambahkan sedikit kompleksitas, Anda dapat mencocokkan 'Nick' atau 'nick' dengan polanya [Nn]ick. Bagian dalam tanda kurung siku adalah kelas karakter , yang artinya cocok dengan salah satu karakter terlampir. Anda juga dapat menggunakan rentang dalam kelas karakter, sehingga [a-c]cocok dengan 'a' atau 'b' atau 'c'.

Polanya .spesial: daripada mencocokkan titik literal saja, pola ini cocok dengan karakter apa saja . Itu sama secara konseptual dengan kelas karakter yang sangat besar [-.?+%$A-Za-z0-9...].

Pikirkan kelas karakter sebagai menu: pilih satu saja.

Pintasan yang bermanfaat

Menggunakan .dapat menghemat banyak mengetik, dan ada cara pintas lainnya untuk pola umum. Katakanlah Anda ingin mencocokkan angka: satu cara untuk menulis itu [0-9]. Digit adalah target pertandingan yang sering, jadi Anda bisa menggunakan pintasan \d. Lainnya adalah \s(spasi putih) dan \w(karakter kata: alfanumerik atau garis bawah).

Varian huruf besar adalah pelengkap mereka, jadi \Scocok dengan karakter non- spasi putih, misalnya.

Sekali saja tidak cukup

Dari sana, Anda dapat mengulangi bagian dari pola Anda dengan penjumlahan . Misalnya, polanya ab?ccocok dengan 'abc' atau 'ac' karena ?quantifier menjadikan subpattern yang dimodifikasi opsional. Pengukur lainnya adalah

  • * (nol kali atau lebih)
  • + (satu kali atau lebih)
  • {n}(tepat n kali)
  • {n,}(setidaknya n kali)
  • {n,m}(setidaknya n kali tetapi tidak lebih dari m kali)

Dengan menyatukan beberapa blok ini, polanya [Nn]*ickcocok dengan semuanya

  • ick
  • Nick
  • nick
  • Nnick
  • nNick
  • nnick
  • (dan seterusnya)

Pertandingan pertama menunjukkan pelajaran penting: *selalu berhasil! Pola apa pun bisa cocok dengan nol kali.

Beberapa contoh bermanfaat lainnya:

  • [0-9]+(dan yang setara \d+) cocok dengan bilangan bulat non-negatif
  • \d{4}-\d{2}-\d{2} tanggal pertandingan diformat seperti 2019-01-01

Pengelompokan

Kuantifikasi mengubah pola ke kiri langsung. Anda mungkin berharap 0abc+0mencocokkan '0abc0', '0abcabc0', dan sebagainya, tetapi polanya langsung di sebelah kiri quantifier plus adalah c. Ini berarti 0abc+0cocok dengan '0abc0', '0abcc0', '0abccc0', dan seterusnya.

Untuk mencocokkan satu atau lebih urutan 'abc' dengan nol di ujungnya, gunakan 0(abc)+0. Tanda kurung menunjukkan suatu subpattern yang dapat dikuantifikasi sebagai satu unit. Ini juga umum untuk mesin ekspresi reguler untuk menyimpan atau "menangkap" bagian dari teks input yang cocok dengan grup yang di-kurung. Mengekstrak bit dengan cara ini jauh lebih fleksibel dan lebih sedikit kesalahan daripada menghitung indeks dan substr.

Alternasi

Sebelumnya, kami melihat satu cara untuk mencocokkan 'Nick' atau 'nick'. Lain adalah dengan bergantian seperti pada Nick|nick. Ingatlah bahwa pergantian mencakup segala sesuatu di sebelah kirinya dan segala sesuatu di sebelah kanannya. Gunakan pengelompokan tanda kurung untuk membatasi ruang lingkup |, misalnya , (Nick|nick).

Sebagai contoh lain, Anda ekuivalen bisa menulis [a-c]seperti a|b|c, tapi ini mungkin suboptimal karena banyak implementasi mengasumsikan alternatif akan memiliki panjang lebih besar dari 1.

Lolos

Meskipun beberapa karakter cocok dengan diri mereka sendiri, yang lain memiliki makna khusus. Pola\d+ tidak cocok dengan garis miring terbalik diikuti oleh huruf kecil D diikuti oleh tanda plus: untuk mendapatkan itu, kita akan gunakan \\d\+. Sebuah backslash menghapus arti khusus dari karakter berikut.

Kerakusan

Pengukur ekspresi reguler adalah serakah. Ini berarti mereka mencocokkan teks sebanyak mungkin sambil membiarkan seluruh pola cocok dengan sukses.

Misalnya, katakan inputnya

"Halo," katanya, "apa kabar?"

Anda mungkin berharap ".+" untuk mencocokkan hanya 'Halo,' dan kemudian akan terkejut ketika Anda melihat bahwa itu cocok dari 'Halo' sepanjang jalan melalui 'Anda?'.

Untuk beralih dari serakah ke apa yang Anda anggap berhati-hati, tambahkan ekstra ?ke quantifier. Sekarang Anda mengerti caranya \((.+?)\), contoh dari pertanyaan Anda berfungsi. Ini cocok dengan urutan kurung kiri literal, diikuti oleh satu atau lebih karakter, dan diakhiri oleh kurung kanan.

Jika input Anda adalah '(123) (456)', maka tangkapan pertama adalah '123'. Penjumlah non-serakah ingin mengizinkan sisa pola untuk mulai mencocokkan sesegera mungkin.

(Mengenai kebingunganmu, aku tidak tahu dialek ekspresi reguler mana ((.+?)) akan melakukan hal yang sama. Aku curiga ada sesuatu yang hilang dalam transmisi di suatu tempat di sepanjang jalan.)

Jangkar

Gunakan pola khusus ^untuk mencocokkan hanya di awal input Anda dan $hanya cocok di akhir. Membuat "bookends" dengan pola Anda di mana Anda berkata, "Saya tahu apa yang ada di depan dan belakang, tetapi berikan saya semuanya di antara" adalah teknik yang berguna.

Katakanlah Anda ingin mencocokkan komentar dari formulir

-- This is a comment --

kamu akan menulis ^--\s+(.+)\s+--$.

Bangun sendiri

Ekspresi reguler bersifat rekursif, jadi sekarang setelah Anda memahami aturan dasar ini, Anda dapat menggabungkannya sesuka Anda.

Alat untuk menulis dan men-debug regex:

Buku

Sumber daya gratis

Catatan kaki

†: Pernyataan di atas yang .cocok dengan karakter apa pun adalah penyederhanaan untuk tujuan pedagogis yang tidak sepenuhnya benar. Dot cocok dengan karakter apa pun kecuali baris baru, "\n"tetapi dalam praktiknya Anda jarang mengharapkan pola seperti .+melewati batas baris baru. Perl regex memiliki /ssaklar dan Java Pattern.DOTALL, misalnya, untuk .mencocokkan karakter apa pun. Untuk bahasa yang tidak memiliki fitur seperti itu, Anda dapat menggunakan sesuatu seperti [\s\S]untuk mencocokkan "spasi putih atau non-spasi putih", dengan kata lain apa saja.

Greg Bacon
sumber
14
Anda juga dapat menggunakan metode coba-coba dan daripada mengikuti tester dan debugger regex online dapat sangat membantu: regex101.com
Juraj.Lorinc
2
Perlu disebutkan bahwa, meskipun memiliki pola yang sama, a{,m}bukanlah hal, setidaknya dalam Javascript, Perl, dan Python.
Dana Gugatan Monica
2
Akan sangat berharga untuk menyebutkan bahwa ada berbagai jenis mesin ekspresi reguler dengan semua memiliki set fitur dan aturan sintaksis yang berbeda.
hek2mgl
1
hackr.io/tutorials/learn-regular-expressions-regex adalah tempat yang bagus untuk menemukan tutorial regex online terbaik. Semua tutorial di sini diajukan dan direkomendasikan (diunggah seperti SO) oleh komunitas pemrograman.
Saurabh Hooda
2
Hargai usaha Anda untuk membawa semuanya ke sini secara singkat.
Saurabh Tiwari