Ada kutipan populer oleh Jamie Zawinski :
Beberapa orang, ketika dihadapkan dengan masalah, berpikir, "Saya tahu, saya akan menggunakan ekspresi reguler." Sekarang mereka memiliki dua masalah.
Bagaimana kutipan ini dipahami?
Ada kutipan populer oleh Jamie Zawinski :
Beberapa orang, ketika dihadapkan dengan masalah, berpikir, "Saya tahu, saya akan menggunakan ekspresi reguler." Sekarang mereka memiliki dua masalah.
Bagaimana kutipan ini dipahami?
Jawaban:
Beberapa teknologi pemrograman pada umumnya tidak dipahami dengan baik oleh programmer ( ekspresi reguler , floating point , Perl , AWK , IoC ... dan lainnya ).
Ini bisa menjadi alat yang luar biasa kuat untuk menyelesaikan serangkaian masalah yang tepat. Ekspresi reguler khususnya sangat berguna untuk mencocokkan bahasa reguler. Dan ada inti masalahnya: hanya sedikit orang yang tahu bagaimana mendeskripsikan bahasa reguler (itu bagian dari teori ilmu komputer / linguistik yang menggunakan simbol-simbol lucu - Anda dapat membacanya di hierarki Chomsky ).
Ketika berurusan dengan hal-hal ini, jika Anda salah menggunakannya, tidak mungkin Anda benar-benar menyelesaikan masalah awal Anda. Menggunakan ekspresi reguler untuk mencocokkan HTML (kejadian yang terlalu umum) akan berarti bahwa Anda akan kehilangan case edge. Dan sekarang, Anda masih memiliki masalah asli yang tidak Anda selesaikan, dan bug halus lainnya yang muncul dengan menggunakan solusi yang salah.
Ini bukan untuk mengatakan bahwa ekspresi reguler tidak boleh digunakan, melainkan bahwa seseorang harus bekerja untuk memahami serangkaian masalah yang dapat mereka selesaikan dan tidak dapat memecahkan dan menggunakannya dengan bijaksana.
Kunci untuk memelihara perangkat lunak adalah menulis kode yang dapat dipelihara. Menggunakan ekspresi reguler dapat berlawanan dengan tujuan itu. Saat bekerja dengan ekspresi reguler, Anda telah menulis komputer mini (khususnya otomat keadaan terbatas non-deterministik ) dalam bahasa khusus domain khusus. Sangat mudah untuk menulis 'Hello world' yang setara dalam bahasa ini dan mendapatkan kepercayaan yang belum sempurna di dalamnya, tetapi melangkah lebih jauh perlu dihalangi dengan pemahaman bahasa reguler untuk menghindari penulisan bug tambahan yang bisa sangat sulit diidentifikasi dan diperbaiki (karena mereka bukan bagian dari program tempat ekspresi reguler berada).
Jadi sekarang Anda punya masalah baru; Anda memilih alat ekspresi reguler untuk menyelesaikannya (ketika tidak sesuai), dan Anda memiliki dua bug sekarang, yang keduanya lebih sulit ditemukan, karena mereka tersembunyi di lapisan abstraksi lain.
Ekspresi reguler - terutama yang tidak sepele - berpotensi sulit untuk dikodekan, dipahami, dan dipelihara. Anda hanya perlu melihat jumlah pertanyaan pada Stack Overflow yang ditandai di [regex]
mana si penanya berasumsi bahwa jawaban untuk masalah mereka adalah regex dan kemudian macet. Dalam banyak kasus masalahnya dapat (dan mungkin harus) diselesaikan dengan cara yang berbeda.
Ini berarti, jika Anda memutuskan untuk menggunakan regex Anda sekarang memiliki dua masalah:
Pada dasarnya, saya pikir maksudnya Anda hanya boleh menggunakan regex jika tidak ada cara lain untuk menyelesaikan masalah Anda. Solusi lain mungkin akan lebih mudah untuk dikodekan, dirawat, dan didukung. Mungkin lebih lambat atau kurang efisien, tetapi jika itu tidak kritis, kemudahan pemeliharaan dan dukungan harus menjadi perhatian utama.
Ini sebagian besar lelucon yang dilakukan dengan lidah, meskipun dengan kebenaran.
Ada beberapa tugas yang ekspresi regulernya sangat pas. Saya pernah mengganti 500 baris kode parser keturunan rekursif ditulis secara manual dengan satu ekspresi reguler yang memakan waktu sekitar 10 menit untuk sepenuhnya debug. Orang mengatakan regex sulit dipahami dan didebug, tetapi yang diterapkan dengan tepat hampir tidak sulit untuk didebug sebagai parser besar yang dirancang dengan tangan. Dalam contoh saya, butuh dua minggu untuk men-debug semua kasus tepi dari solusi non-regex.
Namun, untuk parafrase Paman Ben:
Dengan ekspresivitas yang luar biasa, muncul tanggung jawab yang besar.
Dengan kata lain, regex menambahkan ekspresifitas ke bahasa Anda, tetapi hal itu memberi lebih banyak tanggung jawab pada programmer untuk memilih mode ekspresi yang paling mudah dibaca untuk tugas yang diberikan.
Beberapa hal awalnya terlihat seperti tugas yang baik untuk ekspresi reguler, tetapi tidak. Misalnya, apa pun dengan token bersarang, seperti HTML. Terkadang orang menggunakan ekspresi reguler ketika metode yang lebih sederhana lebih jelas. Misalnya, string.endsWith("ing")
lebih mudah dipahami daripada regex yang setara. Kadang-kadang orang mencoba menjejalkan masalah besar menjadi satu regex, di mana memecahnya menjadi lebih baik. Kadang-kadang orang gagal membuat abstraksi yang sesuai, mengulangi suatu regex berulang-ulang alih-alih menciptakan fungsi yang dinamai dengan baik untuk melakukan pekerjaan yang sama (mungkin diimplementasikan secara internal dengan sebuah regex).
Untuk beberapa alasan, regex memiliki kecenderungan aneh untuk membuat titik buta dengan prinsip-prinsip rekayasa perangkat lunak normal seperti tanggung jawab tunggal dan KERING. Itu sebabnya bahkan orang-orang yang mencintai mereka terkadang merasa bermasalah.
Jeff Atwood mengeluarkan interpretasi berbeda dalam posting blog yang membahas kutipan ini: Ekspresi Reguler: Sekarang Anda Punya Dua Masalah (terima kasih kepada Euphoric atas tautannya)
Menganalisa teks lengkap posting Jamie di utas asli 1997, kami menemukan yang berikut:
Sifat Perl mendorong penggunaan ekspresi reguler hampir dengan mengesampingkan semua teknik lainnya; mereka jauh dan merupakan cara yang paling "jelas" (paling tidak, bagi orang-orang yang tidak tahu lebih baik) untuk beralih dari titik A ke titik B.
Kutipan pertama terlalu glib untuk dianggap serius. Tapi ini, saya sepenuhnya setuju. Inilah intinya yang Jamie coba buat: bukan bahwa ekspresi reguler itu jahat, tapi itu terlalu sering menggunakan ekspresi reguler itu jahat.
Bahkan jika Anda benar - benar memahami ekspresi reguler, Anda mengalami masalah The Golden Hammer , mencoba menyelesaikan masalah dengan ekspresi reguler, ketika itu akan lebih mudah dan lebih jelas untuk melakukan hal yang sama dengan kode reguler (lihat juga CodingHorror: Regex use vs. penyalahgunaan Regex ).
Ada posting blog lain yang melihat konteks kutipan, dan masuk ke lebih detail daripada Atwood: Blog Jeffrey Friedl: Sumber kutipan terkenal "Sekarang Anda punya dua masalah"
Ada beberapa hal yang terjadi dengan kutipan ini.
The kutipan adalah penyajian kembali lelucon sebelumnya:
Setiap kali menghadapi masalah, beberapa orang mengatakan "Mari kita gunakan AWK." Sekarang, mereka memiliki dua masalah. - D. Tilbrook
Ini adalah lelucon dan penggalian nyata, tetapi juga cara menyoroti regex sebagai solusi buruk dengan menghubungkannya dengan solusi buruk lainnya. Ini adalah momen besar yang sangat serius .
Bagi saya — ingatkan Anda, kutipan ini sengaja terbuka untuk interpretasi — artinya langsung ke depan. Cukup mengumumkan gagasan menggunakan ekspresi reguler belum menyelesaikan masalah. Selain itu, Anda telah meningkatkan kompleksitas kognitif kode dengan menambahkan bahasa tambahan dengan aturan yang berbeda dari bahasa apa pun yang Anda gunakan.
Meskipun lucu sebagai lelucon, Anda harus membandingkan kompleksitas solusi non-regex dengan kompleksitas solusi regex + kompleksitas tambahan termasuk regex. Mungkin bermanfaat untuk menyelesaikan masalah dengan regex, meskipun ada biaya tambahan untuk menambahkan regex.
RegulerExpressionssekarangmenutuppelatihanuntukmemeliharaisetelahnyadapatterformatkeduanya; memangadapatdilakukansecara lebih baikuntukadalambeberapabarang inidalamnyapemungkinannyadimempertarakanpertanggungjawabankarenaberlakuuntukmemformatandan orang yang tidak mengetahuiatau secara langsung.
(Ekspresi Reguler tidak lebih buruk untuk dibaca atau dipelihara daripada konten yang tidak diformat lainnya; memang regex mungkin lebih mudah dibaca daripada teks ini di sini - tetapi sayangnya mereka memiliki reputasi yang buruk karena beberapa implementasi tidak memungkinkan pemformatan dan orang pada umumnya tidak tahu kamu bisa melakukannya.)
Berikut ini contoh sepele:
^(?:[^,]*+,){21}[^,]*+$
Yang sebenarnya tidak terlalu sulit untuk dibaca atau dikelola, tetapi bahkan lebih mudah ketika terlihat seperti ini:
(?x) # enables comments, so this whole block can be used in a regex.
^ # start of string
(?: # start non-capturing group
[^,]*+ # as many non-commas as possible, but none required
, # a comma
) # end non-capturing group
{21} # 21 of previous entity (i.e. the group)
[^,]*+ # as many non-commas as possible, but none required
$ # end of string
Itu sedikit contoh berlebihan (berkomentar $
mirip dengan berkomentar i++
) tetapi jelas tidak boleh ada masalah membaca, memahami, dan mempertahankannya.
Selama Anda jelas tentang kapan ekspresi reguler cocok dan ketika mereka ide yang buruk, tidak ada yang salah dengan mereka, dan sebagian besar kutipan JWZ tidak benar-benar berlaku.
*+
? Bagaimana itu berbeda (secara fungsional) dari adil *
?
*+
hal ini; semuanya berlabuh dan dapat dicocokkan dalam satu lintasan oleh otomat yang dapat menghitung hingga 22. Pengubah yang benar pada set non-koma itu baru saja tua *
. (Terlebih lagi, seharusnya tidak ada perbedaan antara algoritma pencocokan serakah dan non-serakah di sini. Ini adalah kasus yang sangat sederhana.)
Selain jawaban ChrisF - bahwa ekspresi reguler "sulit untuk dikodekan, dipahami, dan dipertahankan", ada yang lebih buruk: mereka hanya cukup kuat untuk mengelabui orang agar mencoba menggunakannya untuk menguraikan hal-hal yang tidak dapat mereka lakukan, seperti HTML. Lihat banyak pertanyaan di SO pada "bagaimana cara menguraikan HTML?" Misalnya, satu - satunya jawaban paling epik dalam semua SO!
Ekspresi reguler sangat kuat, tetapi mereka memiliki satu masalah kecil dan satu besar; mereka sulit untuk ditulis, dan hampir mustahil untuk dibaca.
Dalam kasus terbaik penggunaan ekspresi reguler memecahkan masalah, jadi Anda hanya memiliki masalah pemeliharaan kode yang rumit. Jika Anda tidak mendapatkan persamaan reguler dengan benar, Anda memiliki masalah asli dan masalah dengan kode yang tidak dapat dibaca yang tidak berfungsi.
Terkadang ekspresi reguler disebut sebagai kode hanya-tulis. Dihadapkan dengan ekspresi reguler yang perlu diperbaiki, seringkali lebih cepat untuk memulai dari awal daripada mencoba memahami ekspresi.
Masalahnya adalah bahwa regex adalah binatang yang rumit, dan Anda hanya menyelesaikan masalah Anda jika Anda menggunakan regex dengan sempurna. Jika tidak, Anda memiliki 2 masalah: masalah dan regex asli Anda .
Anda mengklaim bahwa itu dapat melakukan pekerjaan seratus baris kode, tetapi Anda juga bisa membuat argumen bahwa 100 baris kode yang jelas dan ringkas lebih baik daripada satu baris regex.
Jika Anda memerlukan beberapa bukti tentang ini: Anda dapat memeriksa SO Classic ini atau hanya menyisir melalui Tag Regex SO
Arti memiliki dua bagian:
Ketika Anda memintanya pada tahun 2014, akan menarik untuk fokus pada bahasa pemrograman ideologi konteks 1997 dibandingkan dengan konteks saat ini. Saya tidak akan memasuki debat ini di sini tetapi pendapat tentang Perl dan Perl sendiri telah sangat berubah.
Namun, untuk tetap dalam konteks 2013 ( de l'eau a coulé sous les ponts depuis), saya akan menyarankan untuk fokus pada pemeragaan kembali dalam kutipan menggunakan komik XKCD terkenal yang merupakan kutipan langsung dari Jamie Zawinski :
Pertama saya memiliki masalah untuk memahami komik ini karena itu adalah referensi ke kutipan Zawinski, dan kutipan dari lirik lagu Jay-z, dan referensi dari GNU program --help -z
flag 2 , jadi, terlalu banyak budaya bagi saya untuk memahaminya.
Saya tahu itu menyenangkan, saya merasakannya, tetapi saya tidak benar-benar tahu mengapa. Orang-orang sering membuat lelucon tentang Perl dan regex, terutama karena itu bukan bahasa pemrograman paling keren, tidak benar-benar tahu mengapa itu seharusnya menyenangkan ... Mungkin karena penjual Perl melakukan hal-hal konyol .
Jadi kutipan awal tampaknya menjadi lelucon sarkastik berdasarkan masalah kehidupan nyata (sakit?) Yang disebabkan oleh pemrograman dengan alat yang menyakitkan. Sama seperti palu yang bisa melukai tukang batu, pemrograman dengan alat yang bukan yang akan dipilih pengembang jika ia bisa menyakiti (otak, perasaan). Terkadang, debat hebat tentang alat mana yang paling baik terjadi, tetapi hampir tidak berharga karena itu masalah selera Anda atau selera tim pemrograman Anda , alasan budaya atau ekonomi . Komik XKCD lain yang luar biasa tentang ini:
Saya dapat memahami orang-orang merasa sakit dengan regex, dan mereka percaya bahwa alat lain lebih cocok untuk apa regex dirancang untuk. Ketika @ karl-bielefeldt menjawab pertanyaan Anda dengan sangat ekspresif, datang tanggung jawab besar , dan regex sangat peduli dengan hal ini. Jika pengembang tidak peduli bagaimana dia berurusan dengan regex, pada akhirnya akan menyebalkan bagi orang yang akan mempertahankan kode nanti.
Saya akan menyelesaikan dengan jawaban ini tentang pemeragaan kutipan oleh kutipan yang menunjukkan contoh khas dari Perl Best Practices karya Damian Conw ay (buku 2005).
Dia menjelaskan bahwa menulis pola seperti ini:
m{'[^\\']*(?:\\.[^\\']*)*'}
... tidak lebih dapat diterima daripada menulis program seperti ini :
sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;
Tapi itu bisa ditulis ulang , itu masih tidak cantik, tapi setidaknya sekarang bisa bertahan.
# Match a single-quoted string efficiently...
m{ ' # an opening single quote
[^\\']* # any non-special chars (i.e., not backslash or single quote)
(?: # then all of...`
\\ . # any explicitly backslashed char
[^\\']* # followed by any non-special chars
)* # ...repeated zero or more times
' # a closing single quote
}x
Jenis kode berbentuk persegi panjang ini adalah masalah kedua bukan regex yang dapat diformat dengan cara yang jelas, dapat dipelihara dan mudah dibaca.
/* Multiply the first 10 values in an array by 2. */ for (int i = 0 /* the loop counter */; i < 10 /* continue while it is less than 10 */; ++i /* and increment it by 1 in each iteration */) { array[i] *= 2; /* double the i-th element in the array */ }
Jika ada satu hal yang harus Anda pelajari dari ilmu komputer, itu adalah hierarki Chomsky . Saya akan mengatakan bahwa semua masalah dengan ekspresi reguler berasal dari upaya untuk mengurai tata bahasa bebas konteks dengan itu. Saat Anda bisa memaksakan batas (atau berpikir Anda bisa memaksakan batas) ke level bersarang di CFG, Anda mendapatkan ekspresi reguler yang panjang dan kompleks.
Ekspresi reguler lebih cocok untuk tokenisasi daripada parsing skala penuh.
Tetapi, satu set besar hal-hal yang perlu diurai oleh programer dapat diuraikan dengan bahasa reguler (atau, lebih buruk lagi, hampir dapat diuraikan oleh bahasa biasa dan jika Anda hanya menulis sedikit kode lagi ...).
Jadi jika seseorang terbiasa dengan "aha, saya harus memilih teks terpisah, saya akan menggunakan ekspresi reguler", mudah untuk turun rute itu, ketika Anda membutuhkan sesuatu yang lebih dekat dengan otomat push-down, parser CFG atau tata bahasa bahkan lebih kuat. Itu biasanya berakhir dengan air mata.
Jadi, saya pikir kutipannya tidak terlalu membanting regexps, mereka memiliki penggunaannya (dan digunakan dengan baik, mereka memang sangat berguna), tetapi ketergantungan yang berlebihan pada regexps (atau, khususnya, pilihan tidak kritis dari mereka) .
jwz hanya dari kursi goyang dengan kutipan itu. ekspresi reguler tidak berbeda dari fitur bahasa mana pun - mudah kacau, sulit digunakan dengan elegan, kuat di kali, tidak tepat di kali, sering didokumentasikan dengan baik, sering berguna.
hal yang sama dapat dikatakan untuk aritmatika floating point, penutupan, orientasi objek, I / O asinkron, atau apa pun yang Anda dapat nama. jika Anda tidak tahu apa yang Anda lakukan, bahasa pemrograman bisa membuat Anda sedih.
jika menurut Anda regex sulit dibaca, coba baca penerapan parser yang setara untuk mengonsumsi pola yang dimaksud. sering regex menang karena mereka lebih kompak daripada parser penuh ... dan dalam kebanyakan bahasa, mereka lebih cepat juga.
jangan menunda menggunakan ekspresi reguler (atau fitur bahasa lainnya) karena blogger yang mempromosikan diri membuat pernyataan yang tidak memenuhi syarat. coba hal-hal untuk diri sendiri dan lihat apa yang cocok untuk Anda.
Favorit saya, jawaban mendalam untuk ini diberikan oleh Rob Pike yang terkenal dalam posting blog yang direproduksi dari komentar kode Google internal: http://commandcenter.blogspot.ch/2011/08/ regular-expressions-in-lexing- and.html
Rangkumannya bukan karena mereka buruk , tetapi mereka sering digunakan untuk tugas-tugas yang belum tentu cocok, terutama ketika menyangkut lexing dan parsing beberapa input.
Ekspresi reguler sulit untuk ditulis, sulit untuk menulis dengan baik, dan bisa relatif mahal dibandingkan dengan teknologi lain ... Lexers, di sisi lain, cukup mudah untuk menulis dengan benar (jika tidak sekompak), dan sangat mudah untuk diuji. Pertimbangkan untuk menemukan pengidentifikasi alfanumerik. Tidak terlalu sulit untuk menulis regexp (sesuatu seperti "[a-ZA-Z _] [a-ZA-Z_0-9] *"), tetapi sebenarnya tidak terlalu sulit untuk menulis sebagai loop sederhana. Namun, kinerja loop akan jauh lebih tinggi dan akan melibatkan lebih sedikit kode di bawah selimut. Perpustakaan ekspresi reguler adalah hal yang besar. Menggunakan satu untuk mengurai pengidentifikasi seperti menggunakan Ferrari untuk pergi ke toko untuk membeli susu.
Dia mengatakan lebih dari itu, dengan alasan bahwa ekspresi reguler berguna, misalnya pencocokan pola yang sekali pakai dalam editor teks tetapi jarang digunakan dalam kode yang dikompilasi, dan sebagainya. Ini layak dibaca.
Ini terkait dengan epigram # 34 Alan Perlis:
String adalah struktur data yang mencolok dan di mana-mana dilewatkan ada banyak duplikasi proses. Ini adalah kendaraan yang sempurna untuk menyembunyikan informasi.
Jadi jika Anda memilih string karakter sebagai struktur data Anda (dan, tentu saja, kode berbasis regex sebagai algoritma untuk memanipulasinya), Anda memiliki masalah, bahkan jika itu berfungsi: desain yang buruk di sekitar representasi data yang tidak sesuai yang sulit untuk memperpanjang, dan tidak efisien.
Namun, seringkali itu tidak berhasil: masalah asli tidak terpecahkan, dan dalam hal ini Anda memiliki dua masalah.
Regex banyak digunakan untuk penguraian teks yang cepat dan kotor. Mereka adalah alat yang hebat untuk mengekspresikan pola yang sedikit lebih kompleks dari sekadar pencocokan string biasa.
Namun ketika regex mendapatkan masalah server yang lebih kompleks, angkat kepala.
Jadi itu semua terlalu mudah untuk memulai dengan masalah pemrosesan teks, menerapkan ekspresi reguler untuk itu dan berakhir dengan dua masalah, masalah asli yang Anda coba selesaikan dan berurusan dengan ekspresi reguler yang berusaha untuk dipecahkan (tetapi tidak menyelesaikan dengan benar) masalah aslinya.