Ekspresi reguler adalah alat yang ampuh dalam persenjataan programmer, tetapi - ada beberapa kasus ketika mereka bukan pilihan terbaik, atau bahkan benar-benar berbahaya.
Contoh sederhana # 1 adalah parsing HTML dengan regexp - jalan yang dikenal untuk banyak bug. Mungkin, ini juga atribut untuk parsing secara umum.
Tetapi, apakah ada area lain yang jelas tidak boleh digunakan untuk ekspresi reguler?
ps: " Pertanyaan yang Anda ajukan tampaknya subyektif dan kemungkinan akan ditutup. " - jadi, saya ingin menekankan, bahwa saya tertarik pada contoh di mana penggunaan regexps diketahui menyebabkan masalah.
Jawaban:
Jangan gunakan ekspresi reguler:
Ini tidak terbatas pada HTML . XML sederhana yang valid tidak dapat diurai secara wajar dengan ekspresi reguler, bahkan jika Anda tahu skema dan Anda tahu itu tidak akan pernah berubah.
Jangan coba, misalnya, mengurai kode sumber C # . Alih-alih, untuk mendapatkan struktur pohon yang bermakna atau token.
Bagaimana jika Anda harus mencari surat, baik kecil maupun modal? Jika Anda menyukai ekspresi reguler, Anda akan menggunakannya. Tetapi bukankah lebih mudah / cepat / mudah dibaca untuk menggunakan dua pencarian, satu demi satu? Peluangnya dalam kebanyakan bahasa Anda akan mencapai kinerja yang lebih baik dan membuat kode Anda lebih mudah dibaca.
Misalnya kode sampel dalam jawaban Ingo adalah contoh yang baik ketika Anda tidak boleh menggunakan ekspresi reguler. Cukup cari
foo
, lalu untukbar
.Contoh yang baik adalah filter kecabulan. Bukan hanya itu adalah ide yang buruk secara umum untuk mengimplementasikannya, tetapi Anda mungkin tergoda untuk melakukannya dengan menggunakan ekspresi reguler, dan Anda akan melakukannya dengan salah. Ada banyak cara manusia dapat menulis kata, angka, kalimat dan akan dipahami oleh manusia lain, tetapi bukan ekspresi reguler Anda. Jadi, alih-alih menangkap kecabulan nyata, ekspresi reguler Anda akan menghabiskan waktunya untuk menyakiti pengguna lain.
Misalnya, jangan memvalidasi alamat email melalui ekspresi reguler. Dalam kebanyakan kasus, Anda akan melakukannya dengan salah. Dalam kasus yang jarang terjadi, Anda akan melakukannya dengan benar dan selesai dengan horor pengkodean sepanjang 6 343 karakter .
Tanpa alat yang tepat, Anda akan membuat kesalahan. Dan Anda akan melihat mereka pada saat terakhir, atau mungkin tidak pernah. Jika Anda tidak peduli dengan kode bersih, Anda akan menulis string dua puluh baris tanpa komentar, tanpa spasi, tanpa baris baru.
Serius, jika saya mengambil kode Anda dan harus memeriksanya atau memodifikasinya, saya tidak ingin menghabiskan waktu seminggu untuk mencoba memahami dua puluh baris string panjang banyak simbol.
sumber
(?(DEFINE))
pernyataan;) Anda dapat menulis regex yang sangat bersih dengan menggunakan itu dan sebenarnya ketika Anda menggunakan itu Anda akan menulis tata bahasa yang sangat mirip dengan apa yang akan Anda tulis di yacc atau sama;)"<a href='foo'>stuff</a>"
. Regex modern tidak memiliki masalah dengan ini.Yang paling penting: saat bahasa yang Anda parsing bukan bahasa biasa .
HTML bukan bahasa biasa dan menguraikannya dengan ekspresi reguler tidak dimungkinkan (tidak hanya sulit atau kode jalan ke kereta).
sumber
Pada stackoverflow orang sering melihat orang meminta regex yang mencari tahu apakah string yang diberikan tidak mengandung ini atau itu. Ini, IMHO, membalikkan tujuan dari ekspresi reguler. Bahkan jika ada solusi (menggunakan tampilan negatif di belakang pernyataan atau hal-hal semacam itu), sering kali lebih baik menggunakan regex untuk apa itu dibuat dan menangani kasus negatif dengan logika program.
Contoh:
sumber
Dua kasus:
Ketika ada cara yang lebih mudah
Sebagian besar bahasa menyediakan fungsi sederhana seperti INSTR untuk menentukan apakah satu string adalah bagian dari yang lain. Jika itu yang ingin Anda lakukan, gunakan fungsi yang lebih sederhana. Jangan menulis ekspresi reguler Anda sendiri.
Jika ada perpustakaan yang tersedia untuk melakukan manipulasi string kompleks, gunakan daripada menulis ekspresi reguler Anda sendiri.
Ketika ekspresi reguler tidak cukup kuat
sumber
Ekspresi reguler tidak dapat mengidentifikasi struktur rekursif . Ini adalah batasan mendasar.
Ambil JSON - ini adalah format yang cukup sederhana, tetapi karena suatu objek dapat berisi objek lain sebagai nilai anggota (sewenang-wenang dalam), sintaksnya bersifat rekursif dan tidak dapat diuraikan oleh regex. Di sisi lain CSV dapat diurai oleh regex karena tidak mengandung struktur rekursif.
Singkatnya, ungkapan reguler tidak memungkinkan pola merujuk pada dirinya sendiri. Anda tidak bisa mengatakan: pada titik ini dalam sintaksis cocok dengan seluruh pola lagi. Dengan kata lain, ekspresi reguler hanya cocok secara linier, itu tidak mengandung tumpukan yang akan memungkinkannya untuk melacak seberapa dalam itu pola bersarang.
Catatan itu tidak ada hubungannya dengan seberapa kompleks atau berbelit-belit formatnya. Ekspresi S benar-benar sangat sederhana, tetapi tidak dapat diuraikan dengan regex. CSS2 di sisi lain adalah bahasa yang cukup kompleks, tetapi tidak mengandung struktur rekursif dan karenanya dapat diuraikan dengan regex. (Meskipun ini tidak benar untuk CSS3 karena ekspresi CSS, yang memiliki sintaksis rekursif.)
Jadi bukan karena jelek atau kompleks atau rawan kesalahan untuk mem-parsing HTML hanya menggunakan regex. Itu tidak mungkin .
Jika Anda perlu mem-parsing format yang berisi struktur rekursif, Anda harus setidaknya menambah penggunaan ekspresi reguler dengan tumpukan untuk melacak tingkat struktur rekursif. Ini biasanya cara kerja pengurai. Ekspresi reguler digunakan untuk mengenali bagian "linear", sementara kode khusus di luar regex digunakan untuk melacak struktur bersarang.
Biasanya penguraian seperti ini dibagi menjadi beberapa fase terpisah. Tokenisasi adalah fase pertama di mana ekspresi reguler digunakan untuk membagi input menjadi urutan "token" seperti kata-kata, tanda baca, tanda kurung dll. Parsing adalah fase berikutnya di mana token ini diuraikan menjadi struktur hierarkis, pohon sintaksis.
Jadi, ketika Anda mendengar bahwa HTML atau C # tidak dapat diuraikan dengan ekspresi reguler, perlu diketahui bahwa ekspresi reguler masih merupakan bagian penting dari parser. Anda tidak bisa menguraikan bahasa seperti itu hanya dengan menggunakan ekspresi reguler dan tidak ada kode pembantu.
sumber