--Edit-- Jawaban saat ini memiliki beberapa ide berguna tetapi saya ingin sesuatu yang lebih lengkap sehingga saya dapat 100% memahami dan menggunakan kembali; itulah mengapa saya menetapkan bounty. Juga gagasan yang bekerja di mana-mana lebih baik bagi saya daripada tidak seperti sintaks standar\K
Pertanyaan ini adalah tentang bagaimana saya bisa mencocokkan pola kecuali beberapa situasi s1 s2 s3. Saya memberikan contoh spesifik untuk menunjukkan maksud saya tetapi lebih memilih jawaban umum yang saya dapat 100% mengerti sehingga saya dapat menggunakannya kembali dalam situasi lain.
Contoh
Saya ingin mencocokkan lima digit menggunakan \b\d{5}\b
tetapi tidak dalam tiga situasi s1 s2 s3:
s1: Bukan pada baris yang diakhiri dengan titik seperti kalimat ini.
s2: Tidak dimanapun di dalam parens.
s3: Tidak di dalam blok yang dimulai dengan if(
dan diakhiri dengan//endif
Saya tahu bagaimana menyelesaikan salah satu dari s1 s2 s3 dengan lookahead dan lookbehind, terutama di C # lookbehind atau \K
di PHP.
Misalnya
s1 (?m)(?!\d+.*?\.$)\d+
s3 dengan C # lookbehind (?<!if\(\D*(?=\d+.*?//endif))\b\d+\b
s3 dengan PHP \ K (?:(?:if\(.*?//endif)\D*)*\K\d+
Tapi campuran kondisi bersama membuat kepalaku meledak. Kabar yang lebih buruk lagi adalah saya mungkin perlu menambahkan kondisi lain s4 s5 di lain waktu.
Kabar baiknya adalah, saya tidak peduli jika saya memproses file menggunakan bahasa yang paling umum seperti PHP, C #, Python, atau mesin cuci tetangga saya. :) Saya cukup banyak pemula di Python & Java tetapi tertarik untuk belajar jika ada solusi.
Jadi saya datang ke sini untuk melihat apakah seseorang memikirkan resep yang fleksibel.
Petunjuknya oke: Anda tidak perlu memberi saya kode lengkap. :)
Terima kasih.
\K
tidak ada sintaks php khusus. Harap uraikan dan klarifikasi apa yang ingin Anda katakan. Jika Anda bertujuan memberi tahu kami bahwa Anda tidak memerlukan solusi yang "rumit", Anda harus mengatakan apa yang rumit untuk Anda dan mengapa."if("
buka paren ditutup, bukan dengan a")"
, melainkan dengan"//endif"
:? Dan jika untuk s3 Anda benar-benar bermaksud bahwa klausa if harus ditutup dengan"//endif)"
:, maka persyaratan s3 adalah bagian dari s2.especially in C# lookbehind or \K in PHP
... Tapi C # lihat di belakang bukan hanya C # itu. NET jadi Anda bisa mengeluh juga Saya katakan C # bukan .NET :) Dan sebagai balasan saya katakan Ruby bukan Onigurama itu buruk juga ... Apakah ada bahasa lain yang menggunakan PCRE? Tidak berbicara tentang Notepad ++ atau alat server ini adalah pertanyaan tentang penggunaan fitur dalam bahasa Saya harap penjelasan dan maaf jika terlihat salahJawaban:
Hans, saya akan mengambil umpan dan menyempurnakan jawaban saya sebelumnya. Anda bilang ingin "sesuatu yang lebih lengkap" jadi saya harap Anda tidak keberatan dengan jawaban yang panjang — hanya mencoba menyenangkan. Mari kita mulai dengan beberapa latar belakang.
Pertama, ini adalah pertanyaan yang bagus. Sering ada pertanyaan tentang mencocokkan pola tertentu kecuali dalam konteks tertentu (misalnya, dalam blok kode atau di dalam tanda kurung). Pertanyaan-pertanyaan ini sering kali menimbulkan solusi yang cukup canggung. Jadi pertanyaan Anda tentang berbagai konteks merupakan tantangan khusus.
Mengherankan
Anehnya, setidaknya ada satu solusi efisien yang umum, mudah diterapkan, dan menyenangkan untuk dipelihara. Ia bekerja dengan semua ragam regex yang memungkinkan Anda untuk memeriksa grup tangkapan dalam kode Anda. Dan itu kebetulan menjawab sejumlah pertanyaan umum yang mungkin pada awalnya terdengar berbeda dari pertanyaan Anda: "cocokkan semuanya kecuali Donat", "ganti semua kecuali ...", "cocokkan semua kata kecuali yang ada di daftar hitam ibu saya", "abaikan tag "," cocok dengan suhu kecuali dicetak miring "...
Sayangnya, teknik ini tidak begitu dikenal: Saya memperkirakan bahwa dalam dua puluh pertanyaan SO yang dapat menggunakannya, hanya satu yang memiliki satu jawaban yang menyebutkannya — yang berarti mungkin satu dari lima puluh atau enam puluh jawaban. Lihat pertukaran saya dengan Kobi di komentar. Teknik ini dijelaskan secara mendalam dalam artikel ini yang menyebutnya (secara optimis) sebagai "trik regex terbaik yang pernah ada". Tanpa membahas terlalu detail, saya akan mencoba memberi Anda pemahaman yang kuat tentang cara kerja teknik ini. Untuk detail lebih lanjut dan contoh kode dalam berbagai bahasa, saya mendorong Anda untuk melihat sumber daya itu.
Variasi yang Lebih Diketahui
Ada variasi menggunakan sintaks khusus untuk Perl dan PHP yang melakukan hal yang sama. Anda akan melihatnya di SO di tangan master regex seperti CasimiretHippolyte dan HamZa . Saya akan memberi tahu Anda lebih banyak tentang ini di bawah, tetapi fokus saya di sini adalah pada solusi umum yang berfungsi dengan semua rasa regex (selama Anda dapat memeriksa grup tangkapan dalam kode Anda).
Fakta Kunci
Faktanya, triknya adalah mencocokkan berbagai konteks yang tidak kita inginkan (merangkai konteks ini menggunakan
|
OR / alternasi) untuk "menetralkannya". Setelah pencocokan semua konteks yang tidak diinginkan, bagian akhir dari pergantian cocok apa yang kita lakukan inginkan dan menangkap ke Grup 1.Resep umumnya adalah
Ini akan cocok
Not_this_context
, tetapi dalam arti bahwa pertandingan tersebut masuk ke tempat sampah, karena kita tidak akan melihat pertandingan secara keseluruhan: kita hanya melihat tangkapan Grup 1.Dalam kasus Anda, dengan angka Anda dan tiga konteks Anda untuk diabaikan, kami dapat melakukan:
Perhatikan bahwa karena kami benar-benar mencocokkan s1, s2, dan s3 daripada mencoba menghindarinya dengan lookarounds, ekspresi individu untuk s1, s2 dan s3 dapat tetap jelas sebagai hari. (Mereka adalah subekspresi di setiap sisi a
|
)Seluruh ekspresi bisa ditulis seperti ini:
Lihat demo ini (tapi fokus pada grup pengambilan di panel kanan bawah.)
Jika Anda secara mental mencoba membagi regex ini di setiap
|
pembatas, sebenarnya itu hanya rangkaian empat ekspresi yang sangat sederhana.Untuk rasa yang mendukung spasi bebas, bacaan ini sangat baik.
Ini sangat mudah dibaca dan dipelihara.
Memperluas regex
Saat Anda ingin mengabaikan lebih banyak situasi s4 dan s5, Anda menambahkannya di lebih banyak alternatif di sebelah kiri:
Bagaimana cara kerjanya?
Konteks yang tidak Anda inginkan ditambahkan ke daftar alternatif di sebelah kiri: mereka akan cocok, tetapi kecocokan keseluruhan ini tidak pernah diperiksa, jadi mencocokkannya adalah cara untuk meletakkannya di "tempat sampah".
Konten yang Anda inginkan, bagaimanapun, disimpan ke Grup 1. Anda kemudian harus memeriksa secara terprogram bahwa Grup 1 telah disetel dan tidak kosong. Ini adalah tugas pemrograman yang sepele (dan nanti kita akan membicarakan cara melakukannya), terutama mengingat hal itu membuat Anda memiliki regex sederhana yang dapat Anda pahami secara sekilas dan merevisi atau memperluas sesuai kebutuhan.
Saya tidak selalu menyukai visualisasi, tapi yang satu ini menunjukkan betapa sederhananya metodenya. Setiap "baris" sesuai dengan pertandingan potensial, tetapi hanya keuntungan yang diambil ke dalam Grup 1.
Demo Debuggex
Variasi Perl / PCRE
Berbeda dengan solusi umum di atas, terdapat variasi Perl dan PCRE yang sering terlihat di SO, setidaknya di tangan Dewa regex seperti @CasimiretHippolyte dan @HamZa. Ini:
Dalam kasus Anda:
Variasi ini sedikit lebih mudah digunakan karena konten yang cocok dengan konteks s1, s2 dan s3 dilewati begitu saja, jadi Anda tidak perlu memeriksa tangkapan Grup 1 (perhatikan tanda kurung tidak ada). Pertandingan hanya berisi
whatYouWant
Perhatikan bahwa
(*F)
,(*FAIL)
dan(?!)
semuanya sama. Jika Anda ingin lebih kabur, Anda bisa menggunakan(*SKIP)(?!)
demo untuk versi ini
Aplikasi
Berikut adalah beberapa masalah umum yang seringkali dapat diselesaikan dengan mudah oleh teknik ini. Anda akan melihat bahwa pilihan kata dapat membuat beberapa masalah ini terdengar berbeda padahal sebenarnya mereka hampir identik.
<a stuff...>...</a>
?<i>
tag atau cuplikan javascript (ketentuan lainnya)?Bagaimana Memprogram Tangkapan Grup 1
Anda tidak memberikan kode, tetapi, untuk penyelesaiannya ... Kode untuk memeriksa Grup 1 jelas akan bergantung pada bahasa pilihan Anda. Bagaimanapun itu tidak boleh menambahkan lebih dari beberapa baris ke kode yang akan Anda gunakan untuk memeriksa kecocokan.
Jika ragu, saya sarankan Anda melihat bagian contoh kode dari artikel yang disebutkan sebelumnya, yang menyajikan kode untuk beberapa bahasa.
Alternatif
Bergantung pada kompleksitas pertanyaan, dan pada mesin regex yang digunakan, ada beberapa alternatif. Berikut ini dua hal yang dapat diterapkan pada sebagian besar situasi, termasuk beberapa ketentuan. Dalam pandangan saya, tidak ada yang semenarik
s1|s2|s3|(whatYouWant)
resepnya, jika hanya karena kejelasan selalu menang.1. Ganti lalu Cocokkan.
Solusi bagus yang terdengar meretas tetapi berfungsi dengan baik di banyak lingkungan adalah bekerja dalam dua langkah. Regex pertama menetralkan konteks yang ingin Anda abaikan dengan mengganti string yang berpotensi konflik. Jika Anda hanya ingin mencocokkan, maka Anda dapat menggantinya dengan string kosong, lalu jalankan kecocokan Anda di langkah kedua. Jika Anda ingin mengganti, Anda dapat mengganti string diabaikan dengan sesuatu yang berbeda, misalnya mengelilingi digit Anda dengan rantai lebar tetap
@@@
. Setelah penggantian ini, Anda bebas mengganti apa yang sebenarnya Anda inginkan, lalu Anda harus mengembalikan@@@
string khusus Anda .2. Pengamatan.
Postingan asli Anda menunjukkan bahwa Anda memahami cara mengecualikan satu ketentuan menggunakan lookarounds. Anda mengatakan bahwa C # bagus untuk ini, dan Anda benar, tetapi itu bukan satu-satunya pilihan. Rasa .NET regex yang ditemukan di C #, VB.NET dan Visual C ++ misalnya, serta
regex
modul yang masih eksperimental untuk digantire
dengan Python, adalah satu-satunya dua mesin yang saya tahu yang mendukung tampilan lebar tak terbatas. Dengan alat ini, satu syarat dalam satu tampilan di belakang dapat menjaga tidak hanya melihat ke belakang tetapi juga pada pertandingan dan di luar pertandingan, menghindari kebutuhan untuk berkoordinasi dengan seorang lookahead. Lebih banyak kondisi? Lebih banyak pencarian.Mendaur ulang regex yang Anda miliki untuk s3 di C #, keseluruhan pola akan terlihat seperti ini.
Tapi sekarang Anda tahu saya tidak merekomendasikan ini, bukan?
Penghapusan
@HamZa dan @Jerry menyarankan agar saya menyebutkan trik tambahan untuk kasus-kasus ketika Anda hanya ingin menghapus
WhatYouWant
. Anda ingat bahwa resep yang cocokWhatYouWant
(memasukkannya ke dalam Grup 1) adalahs1|s2|s3|(WhatYouWant)
, bukan? Untuk menghapus semua instanceWhatYouWant
, Anda mengubah regex menjadiUntuk string pengganti, Anda menggunakan
$1
. Apa yang terjadi di sini adalah untuk setiap instances1|s2|s3
yang cocok, penggantian$1
mengganti instance itu dengan dirinya sendiri (direferensikan oleh$1
). Di sisi lain, ketikaWhatYouWant
cocok, itu diganti dengan grup kosong dan tidak ada yang lain - dan karena itu dihapus. Lihat demo ini , terima kasih @HamZa dan @Jerry karena menyarankan tambahan yang luar biasa ini.Pengganti
Ini membawa kita ke penggantinya, yang akan saya sentuh sebentar.
(*SKIP)(*F)
variasi yang disebutkan di atas agar sesuai dengan yang Anda inginkan, dan lakukan penggantian langsung.Selamat bersenang-senang!
Tidak, tunggu, masih ada lagi!
Ah, nah, aku akan menyimpannya untuk memoarku dalam dua puluh volume, yang akan dirilis Musim Semi mendatang.
sumber
Tarzan
, tetapi tidak saat berada di dalam tanda kutip ganda. The:/no|no|(yes)/
trick regex akan menjadi seperti ini:/"[^"]*"|Tarzan/
(mengabaikan karakter yang lolos). Ini akan bekerja untuk banyak kasus, tetapi gagal sepenuhnya bila diterapkan pada teks JavaScript berlaku sebagai berikut:var bug1 = 'One " quote here. Should match this Tarzan'; var bug2 = "Should not match this Tarzan";
. Trik Rex hanya bekerja ketika SEMUA kemungkinan struktur cocok - dengan kata lain - Anda perlu mengurai teks sepenuhnya untuk menjamin akurasi 100%.var bug1 = /"[^"]*"|(Tarzan)/gi;
dan memiliki efek yang sama (dan contoh kedua ini tentunya bukan kasus tepi). Ada lebih banyak contoh yang dapat saya kutip di mana teknik ini gagal bekerja dengan andal.(?<!\\)"(?:\\"|[^"\r\n])*+"
You don't pull the big gun kecuali Anda punya alasan. Prinsip solusinya masih berlaku. Jika kita tidak dapat mengekspresikan pola untuk diletakkan di sisi kiri, itu lain cerita, kita membutuhkan solusi yang berbeda. Tetapi solusinya melakukan apa yang diiklankan.Lakukan tiga pencocokan berbeda dan tangani kombinasi ketiga situasi tersebut menggunakan logika bersyarat dalam program. Anda tidak perlu menangani semuanya dalam satu regex raksasa.
EDIT: izinkan saya memperluas sedikit karena pertanyaannya menjadi lebih menarik :-)
Ide umum yang coba Anda tangkap di sini adalah untuk mencocokkan dengan pola regex tertentu, tetapi tidak jika ada pola tertentu (bisa berupa angka apa pun) yang ada dalam string pengujian. Untungnya, Anda dapat memanfaatkan bahasa pemrograman Anda: buat ekspresi reguler tetap sederhana dan cukup gunakan bersyarat majemuk. Praktik terbaiknya adalah menangkap ide ini dalam komponen yang dapat digunakan kembali, jadi mari buat kelas dan metode yang mengimplementasikannya:
Jadi di atas, kami menyiapkan string pencarian (lima digit), beberapa string pengecualian ( s1 , s2 , dan s3 Anda ), lalu mencoba mencocokkan dengan beberapa string pengujian. Hasil yang dicetak harus seperti yang ditunjukkan pada komentar di samping setiap string pengujian.
sumber
Persyaratan Anda bahwa tidak ada dalam parens tidak mungkin untuk memuaskan untuk semua kasus. Yaitu, jika Anda entah bagaimana dapat menemukan a
(
ke kiri dan)
ke kanan, itu tidak selalu berarti Anda berada di dalam parens. Misalnya.(....) + 55555 + (.....)
- belum di dalam parens namun ada(
dan)
ke kiri dan kananSekarang Anda mungkin berpikir diri Anda pintar dan mencari
(
ke kiri hanya jika Anda tidak bertemu)
sebelumnya dan sebaliknya ke kanan. Ini tidak akan berfungsi untuk kasus ini:((.....) + 55555 + (.....))
- Di dalam parens meski ada penutup)
dan(
ke kiri dan ke kanan.Tidak mungkin untuk mengetahui apakah Anda berada di dalam kurung menggunakan regex, karena regex tidak dapat menghitung berapa banyak kurung yang telah dibuka dan berapa banyak yang ditutup.
Pertimbangkan tugas yang lebih mudah ini: menggunakan regex, cari tahu apakah semua (mungkin bersarang) tanda kurung dalam string ditutup, yaitu untuk setiap
(
yang perlu Anda temukan)
. Anda akan menemukan bahwa itu tidak mungkin untuk diselesaikan dan jika Anda tidak dapat menyelesaikannya dengan regex maka Anda tidak dapat mengetahui apakah sebuah kata berada di dalam tanda kurung untuk semua kasus, karena Anda tidak dapat mengetahui posisi dalam string jika semua yang sebelumnya(
memiliki yang sesuai)
.sumber
Hans, jika Anda tidak keberatan saya menggunakan mesin cuci tetangga Anda yang disebut perl :)
Diedit: Di bawah kode pseudo:
Diberikan file input.txt:
Dan skrip validator.pl:
Eksekusi:
sumber
Tidak yakin apakah ini akan membantu Anda atau tidak, tetapi saya memberikan solusi dengan mempertimbangkan asumsi berikut -
Namun saya juga mempertimbangkan yang berikut -
if(
blok.Ok ini solusinya -
Saya menggunakan C # dan dengan itu MEF (Microsoft Extensibility Framework) untuk mengimplementasikan parser yang dapat dikonfigurasi. Idenya adalah, gunakan satu parser untuk mengurai dan daftar kelas validator yang dapat dikonfigurasi untuk memvalidasi baris dan mengembalikan benar atau salah berdasarkan validasi. Kemudian Anda dapat menambah atau menghapus validator kapan saja atau menambahkan yang baru jika Anda mau. Sejauh ini saya sudah menerapkan untuk S1, S2 dan S3 yang Anda sebutkan, periksa kelas di poin 3. Anda harus menambahkan kelas untuk s4, s5 jika Anda membutuhkannya di masa mendatang.
Pertama, Buat Antarmuka -
Kemudian datanglah pembaca file dan pemeriksa -
Kemudian datang penerapan checker individu, nama kelas cukup jelas, jadi saya rasa mereka tidak membutuhkan lebih banyak deskripsi.
Program -
Untuk pengujian saya mengambil file contoh @ Tiago
Test.txt
yang memiliki baris berikut -Memberikan keluaran -
Tidak tahu apakah ini akan membantu Anda atau tidak, saya bersenang-senang bermain dengannya .... :)
Bagian terbaiknya adalah, untuk menambahkan kondisi baru yang harus Anda lakukan adalah menyediakan implementasi
IPatternMatcher
, itu akan secara otomatis dipanggil dan dengan demikian akan memvalidasi.sumber
Sama seperti @ zx81
(*SKIP)(*F)
tetapi dengan menggunakan pernyataan kepala tampilan negatif.DEMO
Dengan python, saya akan melakukannya dengan mudah seperti ini,
Keluaran:
sumber