Kapan Anda TIDAK boleh menggunakan Ekspresi Reguler? [Tutup]

50

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.

c69
sumber
9
Parsing HTML dengan regexp bukan hanya "jalan yang dikenal untuk banyak bug". Ini sebenarnya tidak mungkin .
Kramii Reinstate Monica
19
Bukan hanya itu tidak mungkin, itu juga mengarah pada kegilaan dan kutukan abadi
Martin Wickman
3
@ Jörg: Regexp hanyalah singkatan untuk ekspresi reguler.
Joren
3
@ Jorg: Sangat benar bahwa ada perbedaan besar antara ekspresi reguler dalam matematika dan implementasinya dalam pustaka perangkat lunak. Juga benar bahwa sebagian besar pustaka ekspresi reguler memiliki ekstensi yang menempatkan mereka jauh melebihi hanya menerima bahasa biasa, dan menyebut mereka ekspresi reguler tidak selalu begitu tepat. Saya setuju dengan Anda bahwa ada dua konsep yang berbeda. Tetapi mereka memiliki nama yang sama; regexp masih hanya singkatan, bukan istilah itu sendiri. Banyak contoh di situs ini yang menggunakan istilah lengkap untuk pustaka perangkat lunak.
Joren
2
@ Jorg - ini adalah semantik. Walaupun mungkin merupakan ide bagus untuk menyebut pola-pola ini dengan nama yang berbeda (jika hanya untuk menghindari "ekspresi reguler untuk bahasa reguler" fallacy), "regexp" / "ekspresi reguler" bukanlah upaya yang sangat baik, dan hanya mengarah ke kebingungan tambahan.
Kobi

Jawaban:

60

Jangan gunakan ekspresi reguler:

  • Ketika ada parser.

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.

  • Lebih umum, ketika Anda memiliki alat yang lebih baik untuk melakukan pekerjaan Anda.

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 untuk bar.

  • Saat parsing tulisan manusia.

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.

  • Saat memvalidasi beberapa jenis data.

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.

  • Kapan kode Anda akan dibaca. Dan kemudian baca lagi, dan lagi dan lagi, setiap kali oleh pengembang yang berbeda.

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.

Arseni Mourzenko
sumber
9
"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." +1!
funkybro
1
Ini adalah jawaban yang jauh lebih baik daripada saudara tirinya pada stack overflow: stackoverflow.com/questions/7553722/…
Kobi
1
Jika Anda menggunakan Perl / PCRE (dan mungkin juga citarasa regex modern lainnya), bacalah tentang subrutin, yang dinamai kelompok penangkap dan (?(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;)
NikiC
2
Menggunakan ekspresi reguler untuk memilah-milah kata-kata yang masuk daftar hitam adalah kesalahan klb.
Dan Ray
Tidak ada alasan di dunia untuk menghindari melempar regex pada string seperti "<a href='foo'>stuff</a>". Regex modern tidak memiliki masalah dengan ini.
tchrist
18

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).

Matteo
sumber
4
Salah! Jika Anda menggunakan salah satu dari rasa regex modern (Perl, PCRE, Java, .NET, ...) Anda dapat melakukan rekursi dan pernyataan dan dengan demikian dapat menguraikan juga sesuai dengan tata bahasa bebas konteks dan peka konteks.
NikiC
9
@NikiC. Tidak salah. "Citarasa regex modern" bukanlah ekspresi reguler (yang dapat digunakan untuk menguraikan bahasa biasa, karenanya namanya). Saya setuju bahwa dengan PRE Anda dapat melakukan lebih banyak tetapi saya tidak akan menyebut mereka hanya "ekspresi reguler" (seperti pada pertanyaan awal).
Matteo
1
Regex modern jauh melampaui apa yang diajarkan nenek Anda sehingga regex bisa melakukan hal itu karena sarannya tidak penting. Dan bahkan regex primitif dapat menangani sebagian kecil cuplikan HTML. Larangan selimut ini konyol dan tidak realistis. Regex dibuat untuk hal semacam ini. Dan ya, saya tahu apa yang saya bicarakan .
tchrist
12

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:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
Ingo
sumber
1
+1: Beberapa kali, saya menghindari mengkodekan diri saya ke sudut dengan regex dengan berhenti dan bertanya pada diri sendiri "Oke, apa yang saya coba sesuaikan secara spesifik?" alih-alih "Apa yang saya coba hindari?"
5

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

  • Jika Anda membutuhkan parser, gunakan parser.
Kramii Reinstate Monica
sumber
0

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.

JacquesB
sumber