Regex - cara mencocokkan semuanya kecuali pola tertentu
171
Bagaimana cara menulis regex agar cocok dengan string apa pun yang tidak memenuhi pola tertentu? Saya dihadapkan pada situasi di mana saya harus mencocokkan pola (A dan ~ B).
Anda bisa menggunakan pernyataan harapan di masa depan:
(?!999)\d{3}
Contoh ini cocok dengan tiga digit selain 999.
Tetapi jika Anda tidak memiliki implementasi ekspresi reguler dengan fitur ini (lihat Perbandingan Rasa Ekspresi Reguler ), Anda mungkin harus membuat ekspresi reguler dengan fitur dasar sendiri.
Ekspresi reguler yang kompatibel hanya dengan sintaks dasar adalah:
[0-8]\d\d|\d[0-8]\d|\d\d[0-8]
Ini juga cocok dengan urutan tiga digit yang tidak 999.
Lihat-depan bukan sintaks ekspresi reguler standar, itu adalah ekstensi Perl, itu hanya akan bekerja di Perl, PCRE (Perl-Compatible RegEx) atau implementasi non-standar lainnya
Juliano
10
Ini mungkin tidak standar, tetapi tidakkah sebagian besar bahasa modern mendukungnya? Bahasa apa yang tidak mendukung pandangan maju hari ini?
Dia gagal menyebutkannya dalam pertanyaan, tetapi OP sebenarnya menggunakan findstrperintah DOS . Itu hanya memberikan sebagian kecil dari kemampuan yang Anda harapkan untuk ditemukan di alat regex; lookahead tidak ada di antara mereka. (Saya baru saja menambahkan tag findstr sendiri.)
Alan Moore
2
hm, ya, saya temukan sekarang di salah satu komentarnya di posting. Saya melihat Regex di judulnya. Bagaimanapun, jika seseorang menemukan posting ini ketika mencari yang sama untuk ekspresi reguler, seperti yang saya lakukan, mungkin itu bisa membantu seseorang :) terima kasih atas komentar
Aleks
15
Cocokkan dengan pola dan gunakan bahasa host untuk membalikkan hasil boolean dari pertandingan. Ini akan jauh lebih mudah dibaca dan dipelihara.
Kemudian saya berakhir dengan (~ A atau B) alih-alih (A dan ~ B). Itu tidak menyelesaikan masalah saya.
notnot
1
Pseudo-code: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {...}
Ben S
Saya seharusnya lebih jelas - potongannya tidak sepenuhnya independen. Jika A cocok dengan bagian dari string, maka kami peduli jika ~ B cocok dengan sisanya (tetapi tidak harus semuanya). Ini adalah untuk fungsi findstr baris perintah windows, yang saya temukan dibatasi untuk regexs benar, jadi titik diperdebatkan.
notnot
8
tidak, menghidupkan kembali pertanyaan kuno ini karena ada solusi sederhana yang tidak disebutkan. (Temukan pertanyaan Anda saat melakukan riset untuk pencarian karunia regex .)
Saya dihadapkan pada situasi di mana saya harus mencocokkan pola (A dan ~ B).
Regex dasar untuk ini sangat sederhana: B|(A)
Anda mengabaikan pertandingan keseluruhan dan memeriksa tangkapan Grup 1, yang akan berisi A.
Contoh (dengan semua penafian tentang parsing html di regex): A adalah digit, B adalah digit di dalam <a tag
Ini kedengarannya terlalu bagus untuk menjadi kenyataan! Sayangnya, solusi ini tidak universal dan gagal di Emacs, bahkan setelah diganti \ddengan [[:digit:]]. Referensi pertama menyebutkan itu khusus untuk Perl dan PHP: "Ada variasi menggunakan sintaks khusus untuk Perl dan PHP yang mencapai hal yang sama."
miguelmorin
4
Pelengkap bahasa biasa juga merupakan bahasa biasa, tetapi untuk mengkonstruksinya Anda harus membuat DFA untuk bahasa biasa, dan membuat perubahan status yang valid menjadi kesalahan. Lihat ini sebagai contoh. Apa halaman tidak katakan adalah bahwa itu dikonversi /(ac|bd)/menjadi /(a[^c]?|b[^d]?|[^ab])/. Konversi dari DFA kembali ke ekspresi reguler tidak sepele. Lebih mudah jika Anda dapat menggunakan ekspresi reguler tidak berubah dan mengubah semantik dalam kode, seperti yang disarankan sebelumnya.
Jika saya berurusan dengan regex yang sebenarnya maka ini semua akan diperdebatkan. Regex sekarang tampaknya merujuk pada ruang pencocokan pola CSG-ish (?) Samar-samar yang didukung sebagian besar bahasa. Karena saya harus mencocokkan (A dan ~ B), tidak ada cara untuk menghapus negasi dan masih melakukan semuanya dalam satu langkah.
notnot
Lookahead, seperti yang dijelaskan di atas, akan melakukannya jika findstr melakukan sesuatu di luar regangan DFA yang sebenarnya. Semuanya agak aneh dan saya tidak tahu mengapa saya harus melakukan gaya command-line (batch sekarang) ini. Ini hanyalah contoh lain dari tangan saya diikat.
notnot
1
@notnot: Anda menggunakan findstr dari Windows? Maka Anda hanya perlu / v. Seperti: findstr A inputfile | findstr / v B> outputfile.txt Yang pertama cocok dengan semua baris dengan A, yang kedua cocok dengan semua baris yang tidak memiliki B.
Juliano
Terima kasih! Sebenarnya itulah yang saya butuhkan. Saya tidak mengajukan pertanyaan seperti itu, jadi saya masih memberikan jawaban kepada Gumbo untuk jawaban yang lebih umum.
Anda mungkin ingin menyebutkan bahwa Anda harus bergabung lagi.
tomdemuyt
Pendekatan serupa menggunakan replacestr.replace(/re/g, ''), maka tidak perlu bergabung kembali dengan mereka. juga jika Anda melempar trailing yang bagus? seperti str.replace(/\re\s?/g, '')kemudian Anda menyingkirkan duplikat spasi yang Anda miliki dari sesuatu yang diganti di tengah-tengah string
jakecraige
0
Jawaban saya di sini mungkin bisa menyelesaikan masalah Anda juga:
findstr
tag karena semua jawaban di sini tidak valid untuk tag.Jawaban:
Anda bisa menggunakan pernyataan harapan di masa depan:
Contoh ini cocok dengan tiga digit selain
999
.Tetapi jika Anda tidak memiliki implementasi ekspresi reguler dengan fitur ini (lihat Perbandingan Rasa Ekspresi Reguler ), Anda mungkin harus membuat ekspresi reguler dengan fitur dasar sendiri.
Ekspresi reguler yang kompatibel hanya dengan sintaks dasar adalah:
Ini juga cocok dengan urutan tiga digit yang tidak
999
.sumber
Jika Anda ingin mencocokkan kata A dalam string dan tidak cocok dengan kata B. Misalnya: Jika Anda memiliki teks:
Jika Anda ingin mencari baris teks yang MEMILIKI anjing untuk hewan peliharaan dan TIDAK kucing, Anda dapat menggunakan ekspresi reguler ini:
Ini hanya akan menemukan baris kedua:
sumber
findstr
perintah DOS . Itu hanya memberikan sebagian kecil dari kemampuan yang Anda harapkan untuk ditemukan di alat regex; lookahead tidak ada di antara mereka. (Saya baru saja menambahkan tag findstr sendiri.)Cocokkan dengan pola dan gunakan bahasa host untuk membalikkan hasil boolean dari pertandingan. Ini akan jauh lebih mudah dibaca dan dipelihara.
sumber
tidak, menghidupkan kembali pertanyaan kuno ini karena ada solusi sederhana yang tidak disebutkan. (Temukan pertanyaan Anda saat melakukan riset untuk pencarian karunia regex .)
Regex dasar untuk ini sangat sederhana:
B|(A)
Anda mengabaikan pertandingan keseluruhan dan memeriksa tangkapan Grup 1, yang akan berisi A.
Contoh (dengan semua penafian tentang parsing html di regex): A adalah digit, B adalah digit di dalam
<a tag
Regex:
<a.*?<\/a>|(\d+)
Demo (lihat Grup 1 di panel kanan bawah)
Referensi
Cara mencocokkan pola kecuali dalam situasi s1, s2, s3
Cara mencocokkan suatu pola kecuali ...
sumber
\d
dengan[[:digit:]]
. Referensi pertama menyebutkan itu khusus untuk Perl dan PHP: "Ada variasi menggunakan sintaks khusus untuk Perl dan PHP yang mencapai hal yang sama."Pelengkap bahasa biasa juga merupakan bahasa biasa, tetapi untuk mengkonstruksinya Anda harus membuat DFA untuk bahasa biasa, dan membuat perubahan status yang valid menjadi kesalahan. Lihat ini sebagai contoh. Apa halaman tidak katakan adalah bahwa itu dikonversi
/(ac|bd)/
menjadi/(a[^c]?|b[^d]?|[^ab])/
. Konversi dari DFA kembali ke ekspresi reguler tidak sepele. Lebih mudah jika Anda dapat menggunakan ekspresi reguler tidak berubah dan mengubah semantik dalam kode, seperti yang disarankan sebelumnya.sumber
pola - ulang
akan mengembalikan semuanya kecuali polanya.
Tes di sini
sumber
replace
str.replace(/re/g, '')
, maka tidak perlu bergabung kembali dengan mereka. juga jika Anda melempar trailing yang bagus? sepertistr.replace(/\re\s?/g, '')
kemudian Anda menyingkirkan duplikat spasi yang Anda miliki dari sesuatu yang diganti di tengah-tengah stringJawaban saya di sini mungkin bisa menyelesaikan masalah Anda juga:
https://stackoverflow.com/a/27967674/543814
$1
, Anda akan membaca grup$2
.$2
dibuat tidak menangkap di sana, yang akan Anda hindari.Contoh:
Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");
Grup penangkapan pertama menentukan pola yang ingin Anda hindari. Grup menangkap terakhir menangkap yang lainnya. Cukup baca grup itu
$2
,.sumber
lalu gunakan tangkapan kelompok 2 apa ...
sumber