Banyak programmer mengetahui kegembiraan membuat ekspresi reguler yang cepat, akhir-akhir ini sering kali dengan bantuan beberapa layanan web, atau lebih tradisional pada prompt interaktif, atau mungkin menulis skrip kecil yang memiliki ekspresi reguler dalam pengembangan, dan kumpulan kasus uji . Dalam kedua kasus tersebut, prosesnya berulang dan cukup cepat: tetap meretas string yang tampak samar sampai cocok dan menangkap apa yang Anda inginkan dan akan menolak apa yang tidak Anda inginkan.
Untuk kasus sederhana, hasilnya mungkin seperti ini, sebagai regexp Java:
Pattern re = Pattern.compile(
"^\\s*(?:(?:([\\d]+)\\s*:\\s*)?(?:([\\d]+)\\s*:\\s*))?([\\d]+)(?:\\s*[.,]\\s*([0-9]+))?\\s*$"
);
Banyak programmer juga tahu sakitnya harus mengedit ekspresi reguler, atau hanya kode sekitar ekspresi reguler dalam basis kode legacy. Dengan sedikit pengeditan untuk membaginya, regexp di atas masih sangat mudah dipahami bagi siapa pun yang cukup akrab dengan regexps, dan seorang veteran regexp harus segera melihat apa yang dilakukannya (jawab di akhir posting, kalau-kalau ada yang menginginkan latihan tersebut) mencari tahu sendiri).
Namun, hal-hal yang tidak perlu menjadi jauh lebih kompleks untuk regexp menjadi hal yang benar-benar hanya untuk menulis, dan bahkan dengan dokumentasi yang rajin (yang semua orang tentu saja lakukan untuk semua regexps kompleks yang mereka tulis ...), memodifikasi regexps menjadi sebuah tugas yang menakutkan. Ini bisa menjadi tugas yang sangat berbahaya juga, jika regexp tidak diuji unit dengan hati-hati (tetapi setiap orang tentu saja memiliki tes unit komprehensif untuk semua regexps kompleks mereka, baik positif maupun negatif ...).
Jadi, singkatnya, apakah ada solusi baca-tulis / alternatif untuk ekspresi reguler tanpa kehilangan kekuatannya? Bagaimana regexp di atas akan terlihat seperti dengan pendekatan alternatif? Bahasa apa pun baik-baik saja, meskipun solusi multi-bahasa adalah yang terbaik, sampai tingkat regexps multi-bahasa.
Dan kemudian, apa yang dilakukan regexp sebelumnya adalah ini: parsing string angka dalam format 1:2:3.4
, menangkap setiap angka, di mana spasi diizinkan dan hanya 3
diperlukan.
Jawaban:
Sejumlah orang telah menyebutkan komposisi dari bagian yang lebih kecil, tetapi belum ada yang memberikan contoh, jadi inilah milik saya:
Bukan yang paling mudah dibaca, tapi saya merasa lebih jelas dari aslinya.
Selain itu, C # memiliki
@
operator yang dapat ditambahkan ke string untuk menunjukkan bahwa itu harus diambil secara harfiah (tidak ada karakter escape), jadinumber
akan menjadi@"([\d]+)";
sumber
[\\d]+
dan[0-9]+
seharusnya adil\\d+
(well, beberapa mungkin menemukan[0-9]+
lebih mudah dibaca). Saya tidak akan mengedit pertanyaan, tetapi Anda mungkin ingin memperbaiki jawaban ini.\d
akan cocok dengan apa pun yang dianggap bilangan, bahkan dalam sistem penomoran lainnya (Cina, Arab, dll.), Sementara[0-9]
hanya akan cocok dengan angka standar. Saya melakukan standarisasi\\d
, dan memasukkannya ke dalamoptionalDecimal
pola.Kunci untuk mendokumentasikan ekspresi reguler adalah mendokumentasikannya. Terlalu sering orang melemparkan apa yang tampak sebagai derau baris dan membiarkannya begitu saja.
Dalam perl ,
/x
operator di akhir ekspresi reguler menekan spasi putih memungkinkan seseorang untuk mendokumentasikan ekspresi reguler.Ekspresi reguler di atas kemudian menjadi:
Ya, ini sedikit memakan spasi vertikal, meskipun orang bisa mempersingkatnya tanpa mengorbankan terlalu banyak keterbacaan.
Melihat ungkapan reguler ini orang dapat melihat cara kerjanya (dan tidak bekerja). Dalam hal ini, regex ini akan cocok dengan string
1
.Pendekatan serupa dapat diambil dalam bahasa lain. Opsi python re.VERBOSE bekerja di sana.
Perl6 (contoh di atas adalah untuk perl5) mengambil ini lebih jauh dengan konsep aturan yang mengarah pada struktur yang bahkan lebih kuat daripada PCRE (ini menyediakan akses ke tata bahasa lain (bebas konteks dan sensitif konteks) daripada yang biasa dan diperpanjang reguler).
Di Jawa (di mana contoh ini diambil dari), seseorang dapat menggunakan penggabungan string untuk membentuk regex.
Memang, ini menciptakan lebih banyak
"
dalam string yang mungkin menyebabkan kebingungan di sana, dapat lebih mudah dibaca (terutama dengan penyorotan sintaks pada sebagian besar IDE) dan didokumentasikan.Kuncinya adalah mengenali kekuatan dan "menulis sekali" sifat yang sering jatuh ke ekspresi reguler. Menulis kode untuk menghindari hal ini secara defensif sehingga ekspresi reguler tetap jelas dan dapat dimengerti adalah kuncinya. Kami memformat kode Java untuk kejelasan - ekspresi reguler tidak berbeda ketika bahasa memberi Anda opsi untuk melakukannya.
sumber
Mode "verbose" yang ditawarkan oleh beberapa bahasa dan perpustakaan adalah salah satu jawaban untuk masalah ini. Dalam mode ini, spasi putih dalam string regexp dihapus (jadi Anda harus menggunakan
\s
) dan komentar dimungkinkan. Berikut adalah contoh singkat dalam Python yang mendukung ini secara default:Dalam bahasa apa pun yang tidak, menerapkan penerjemah dari verbose ke mode "normal" harus menjadi tugas yang sederhana. Jika Anda khawatir tentang keterbacaan regexps Anda, Anda mungkin akan membenarkan investasi waktu ini dengan mudah.
sumber
Setiap bahasa yang menggunakan regex memungkinkan Anda untuk menyusunnya dari blok yang lebih sederhana agar lebih mudah dibaca, dan dengan sesuatu yang lebih rumit daripada (atau serumit) contoh Anda, Anda harus mengambil keuntungan dari opsi itu. Masalah khusus dengan Jawa dan banyak bahasa lainnya adalah bahwa mereka tidak memperlakukan ekspresi reguler sebagai warga negara "kelas satu", sebaliknya mengharuskan mereka untuk menyelinap ke dalam bahasa melalui string literal. Ini berarti banyak tanda kutip dan garis miring terbalik yang sebenarnya bukan bagian dari sintaks regex dan membuat hal-hal sulit dibaca, dan itu juga berarti bahwa Anda tidak bisa lebih mudah dibaca daripada itu tanpa secara efektif mendefinisikan bahasa mini dan penerjemah Anda sendiri.
Cara prototipikal yang lebih baik untuk mengintegrasikan ekspresi reguler tentu saja Perl, dengan opsi spasi putih dan operator regex-quote. Perl 6 memperluas konsep membangun regex dari bagian ke tata bahasa rekursif yang sebenarnya, yang jauh lebih baik untuk digunakan itu benar-benar tidak ada perbandingan sama sekali. Bahasa itu mungkin telah ketinggalan zaman, tetapi dukungan regexnya adalah The Good Stuff (tm).
sumber
Saya suka menggunakan Expresso: http://www.ultrapico.com/Expresso.htm
Aplikasi gratis ini memiliki fitur-fitur berikut yang menurut saya berguna dari waktu ke waktu:
Misalnya, dengan regex yang baru saja Anda kirim, akan terlihat seperti:
Tentu saja, mencobanya bernilai ribuan kata yang menggambarkannya. Harap perhatikan juga bahwa saya mencatat terkait dengan cara apa pun dengan editor aplikasi ini.
sumber
Untuk beberapa hal, mungkin membantu untuk hanya menggunakan tata bahasa seperti BNF. Ini bisa lebih mudah dibaca daripada ekspresi reguler. Alat seperti GoldParser Builder kemudian dapat mengubah tata bahasa menjadi parser yang melakukan pengangkatan berat untuk Anda.
Tata bahasa BNF, EBNF, dll. Bisa lebih mudah dibaca dan dibuat daripada ekspresi reguler yang rumit. GOLD adalah salah satu alat untuk hal-hal seperti itu.
Tautan wiki c2 di bawah ini memiliki daftar alternatif yang memungkinkan yang dapat di-Google, dengan beberapa diskusi tentang mereka. Ini pada dasarnya adalah tautan "lihat juga" untuk melengkapi rekomendasi mesin tata bahasa saya:
Alternatif Untuk Ekspresi Reguler
sumber
Ini adalah pertanyaan lama dan saya tidak melihat penyebutan Verbal, jadi saya pikir saya akan menambahkan informasi itu di sini juga untuk para pencari masa depan. Ekspresi verbal secara khusus dirancang untuk membuat regex manusia dapat dipahami, tanpa perlu mempelajari makna simbol dari regex. Lihat contoh berikut. Saya pikir ini yang terbaik dari apa yang Anda minta.
Contoh ini untuk javascript, Anda dapat menemukan perpustakaan ini sekarang untuk banyak bahasa pemrograman.
sumber
Cara paling sederhana adalah dengan tetap menggunakan regex tetapi membangun ekspresi Anda dari penulisan ekspresi yang lebih sederhana dengan nama deskriptif misalnya http://www.martinfowler.com/bliki/ComposedRegex.html (dan ya ini dari string concat)
namun sebagai alternatif, Anda juga bisa menggunakan parser combin library misalnya http://jparsec.codehaus.org/ yang akan memberi Anda parser yang layak secara rekursif. lagi-lagi kekuatan sesungguhnya di sini berasal dari komposisi (komposisi fungsional kali ini).
sumber
Saya pikir itu layak menyebutkan ekspresi grok logstash . Grok dibangun berdasarkan gagasan menyusun ekspresi parsing panjang dari yang lebih pendek. Ini memungkinkan pengujian yang mudah terhadap blok-blok bangunan ini dan dilengkapi dengan lebih dari 100 pola yang umum digunakan . Selain pola-pola ini, ini memungkinkan penggunaan semua sintaks ekspresi reguler.
Pola di atas dinyatakan dalam grok adalah (Saya menguji di aplikasi debugger tetapi bisa salah):
Bagian dan ruang opsional membuatnya tampak sedikit lebih jelek dari biasanya, tetapi baik di sini maupun dalam kasus lain, menggunakan grok dapat membuat hidup seseorang jauh lebih baik.
sumber
Di F # Anda memiliki modul FsVerbalExpressions . Ini memungkinkan Anda untuk menyusun Regex dari ekspresi verbal, juga memiliki beberapa regex yang sudah dibuat sebelumnya (seperti URL).
Salah satu contoh untuk sintaks ini adalah sebagai berikut:
Jika Anda tidak terbiasa dengan sintaks F #, groupName adalah string "GroupNumber".
Kemudian mereka membuat Ekspresi Verbal (VerbEx) yang mereka buat sebagai "COD (? <GroupNumber> [0-9] {3}) END". Yang kemudian mereka uji pada string "COD123END", di mana mereka mendapatkan grup tangkapan bernama "GroupNumber". Ini menghasilkan 123.
Jujur saya menemukan regex normal jauh lebih mudah untuk dipahami.
sumber
Pertama, pahami bahwa kode yang hanya berfungsi adalah kode yang buruk. Kode yang baik juga perlu melaporkan kesalahan yang ditemukan secara akurat.
Misalnya, jika Anda sedang menulis fungsi untuk mentransfer uang tunai dari akun satu pengguna ke akun pengguna lain; Anda tidak akan hanya mengembalikan boolean "berhasil atau gagal" karena itu tidak memberi tahu si penelepon tentang apa yang salah dan tidak mengizinkan penelepon memberi tahu pengguna dengan benar. Sebagai gantinya, Anda mungkin memiliki satu set kode kesalahan (atau serangkaian pengecualian): tidak dapat menemukan akun tujuan, dana yang tidak mencukupi di akun sumber, izin ditolak, tidak dapat terhubung ke database, terlalu banyak memuat (coba lagi nanti), dll. .
Sekarang pikirkan tentang "parsing serangkaian angka dalam format 1: 2: 3,4" misalnya. Semua regex lakukan adalah melaporkan "lulus / gagal" yang tidak memungkinkan umpan balik yang memadai untuk disajikan kepada pengguna (apakah umpan balik ini adalah pesan kesalahan dalam log, atau GUI interaktif di mana kesalahan ditampilkan merah sebagai tipe pengguna, atau apa pun yang lain). Apa jenis kesalahan yang gagal dijelaskan dengan benar? Karakter buruk di angka pertama, angka pertama terlalu besar, titik dua hilang setelah angka pertama, dll.
Untuk mengubah "kode buruk yang hanya berfungsi" menjadi "kode bagus yang menyediakan kesalahan deskriptif yang memadai" Anda harus memecah regex menjadi banyak regex yang lebih kecil (biasanya, regex yang sangat kecil sehingga lebih mudah untuk melakukannya tanpa regex di tempat pertama) ).
Membuat kode dapat dibaca / dipelihara hanyalah konsekuensi tidak disengaja dari membuat kode tersebut baik.
sumber
:
? Bayangkan kompiler yang hanya memiliki satu pesan kesalahan ("ERROR") yang terlalu bodoh untuk memberi tahu pengguna apa masalahnya. Sekarang bayangkan ribuan situs web yang sama bodohnya dan menampilkan (mis.) "Alamat email buruk" dan tidak lebih.