Ini mungkin terdengar seperti pertanyaan bodoh, tapi saya sudah lama berbicara dengan beberapa rekan pengembang saya dan itu terdengar seperti hal yang menyenangkan untuk dipikirkan.
Begitu; apa pendapat Anda - seperti apa tampilan Regex, yang tidak akan pernah bisa ditandingi oleh string apa pun!
Sunting : Mengapa saya menginginkan ini? Yah, pertama karena saya merasa menarik untuk memikirkan ungkapan seperti itu dan kedua karena saya membutuhkannya untuk naskah.
Dalam skrip itu saya mendefinisikan kamus sebagai Dictionary<string, Regex>
. Ini berisi, seperti yang Anda lihat, string dan ekspresi.
Berdasarkan kamus itu saya membuat metode yang semuanya menggunakan kamus ini hanya sebagai referensi tentang bagaimana mereka harus melakukan pekerjaan mereka, salah satunya cocok dengan regex terhadap file log yang diuraikan.
Jika suatu ekspresi cocok, yang lain Dictionary<string, long>
ditambahkan nilai yang dikembalikan oleh ekspresi. Jadi, untuk menangkap pesan log apa pun yang tidak cocok dengan ekspresi dalam kamus saya membuat grup baru yang disebut "tidak dikenal".
Untuk grup ini segala sesuatu yang tidak cocok dengan yang lain ditambahkan. Tetapi untuk mencegah ekspresi "tidak diketahui" menjadi ketidakcocokan (secara tidak sengaja) pesan-log, saya harus membuat ekspresi yang paling tidak pernah cocok, tidak peduli string apa pun yang saya berikan.
Jadi, di sana Anda punya alasan saya untuk ini "bukan pertanyaan nyata" ...
sumber
Jawaban:
Ini sebenarnya cukup sederhana,
meskipun tergantung pada implementasi / flag*:Akan cocok dengan karakter
a
setelah akhir string. Semoga berhasil.PERINGATAN:
Ungkapan ini mahal - itu akan memindai seluruh baris, menemukan jangkar end-of-line, dan hanya kemudian tidak menemukan
a
dan mengembalikan kecocokan negatif. (Lihat komentar di bawah untuk detail lebih lanjut.)* Awalnya saya tidak terlalu memikirkan regexp mode multiline, di mana
$
juga cocok dengan akhir baris. Bahkan, itu akan cocok dengan string kosong tepat sebelum baris baru , jadi karakter biasa sepertia
tidak pernah bisa muncul setelahnya$
.sumber
$a
. Ini setara Perl$(?:a)
juga sangat lambatperl -Mre=debug -e'$_=a x 50; /$(?:a)/'
.timeit
danpython3
.$a
akan cocok dengan teks literal$a
, karena$
tidak valid sebagai jangkar dalam pola itu.Leverage
negative lookahead
:RE ini merupakan kontradiksi dalam hal dan karenanya tidak akan pernah cocok dengan apa pun.
CATATAN:
Dalam Python, re.match () secara implisit menambahkan anchor awal-dari-string (
\A
) ke awal ekspresi reguler. Jangkar ini penting untuk kinerja: tanpa itu, seluruh string akan dipindai. Mereka yang tidak menggunakan Python ingin menambahkan jangkar secara eksplisit:sumber
(?=x)(?!x)
dan seterusnya (gabungan dari lookaheads yang bertentangan, dan sama untuk lookbehinds), dan banyak dari mereka juga bekerja untuk nilai-nilai sewenang-wenangx
(lookbehinds perlux
s yang cocok dengan string fixed-length).r'a\bc'
:, mencari batas kata yang segera dikelilingi oleh huruf di kedua sisi (varian: karakter non-kata pada kedua sisi).perl -Mre=debug -e'$_=x x 8; /(?!x)x/'
. Anda dapat membuatnya lebih cepat dengan menjangkarnya di awal\A(?!x)x
atau di akhir(?!x)x\z
.perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Salah satu yang terlewatkan:
Itu tidak bisa cocok karena string kosong tidak mengandung batas kata. Diuji dalam Python 2.5.
sumber
\`\b\'
berfungsi, yang menggantikan sintaks Emacs untuk "awal / akhir teks" (sebagai lawan dari "awal / akhir" dari baris ").lihat sekeliling:
(?=a)b
Untuk pemula regex: Tampilan positif di depan
(?=a)
memastikan bahwa karakter berikutnya adalaha
, tetapi tidak mengubah lokasi pencarian (atau menyertakan 'a' dalam string yang cocok). Sekarang karakter berikutnya dikonfirmasikan sebagaia
, bagian yang tersisa dari regex (b
) cocok hanya jika karakter berikutnyab
. Dengan demikian, regex ini cocok hanya jika karakter adalah baika
danb
pada saat yang sama.sumber
a\bc
, di mana\b
ekspresi nol-lebar yang cocok dengan batas kata.Itu tidak dapat muncul di tengah kata, yang kami paksa.
sumber
a
dalam teks.$.
.^
$.^
(?!)
sumber
^
hanya memiliki arti khusus sebagai karakter pertama dari regexp, dan$
hanya memiliki makna khusus pada akhir regexp, kecuali ekspresi reguler adalah ekspresi multi-line./$./
berarti sesuatu yang sama sekali berbeda. Ini berarti cocok dengan nilai saat ini$.
(nomor saluran input) . Bahkan/$(.)/
bisa mencocokkan sesuatu jika Anda menulisuse re '/s';
sebelumnya. (perl -E'say "\n" =~ /$(.)/s || 0'
)^
dan$
hanya khusus pada awal dan akhir (masing-masing) dari pola, sehingga tidak ada$.
atau.^
atau$.^
akan bekerja.(?!)
adalah fitur Perl / PCRE, saya percaya.Pencocokan maksimal
Setidaknya satu
a
diikuti oleh sejumlaha
, tanpa mundur. Kemudian cobalah untuk mencocokkan satu lagia
.atau sub ekspresi Independen
Ini sama dengan menempatkan
a+
dalam sub ekspresi independen, diikuti oleh yang laina
.sumber
Perl 5.10 mendukung kata-kata kontrol khusus yang disebut "kata kerja", yang tertutup secara
(*...)
berurutan. (Bandingkan dengan(?...)
urutan khusus.) Di antara mereka, itu termasuk(*FAIL)
kata kerja yang segera kembali dari ekspresi reguler.Perhatikan bahwa kata kerja juga diterapkan di PCRE segera setelah itu, sehingga Anda dapat menggunakannya dalam PHP atau bahasa lain menggunakan pustaka PCRE juga. (Namun, Anda tidak bisa menggunakan Python atau Ruby. Mereka menggunakan mesin mereka sendiri.)
sumber
\b
cocok dengan batas kata - posisi antara huruf dan huruf (atau batas string).\B
adalah pelengkapnya - ini cocok dengan posisi antara dua huruf atau antara non-huruf.Bersama-sama mereka tidak dapat menandingi posisi apa pun.
Lihat juga:
sumber
^\B\b
. Dalam bahasa di mana "awal teks" dan "awal baris" memiliki sintaks yang berbeda, Anda ingin menggunakan sintaks "awal teks", jika tidak, Anda akan menguji setiap baris. (misalnya dalam Emacs ini akan\`\B\b
atau"\\`\\B\\b"
.)^
ini bermasalah dalam sintaksis regexp tertentu (misalnya POSIX BRE) di mana^
hanya jangkar ketika karakter pertama pola, dan jika tidak cocok dengan^
karakter literal .:)
- ini adalah pertanyaan yang tidak praktis, di mana tujuannya adalah untuk menemukan jawaban yang menarik - bukan jawaban yang efisien. Yang mengatakan, polanya dapat ditolak dalam waktu liner (dengan ukuran string target), sehingga tidak buruk untuk regex - sebagian besar pola di sini adalah sama, dan bahkan^
mungkin linier jika tidak dioptimalkan.Ini sepertinya berhasil:
sumber
$.
. Dalam hal ini Anda harus menggunakan$(.)
atau lebih setara$(?:.)
.$.
akan cocok dengan literal$
diikuti oleh karakter apa pun, karena$
tidak valid sebagai jangkar dalam pola itu.Bagaimana dengan
$^
atau mungkin(?!)
?sumber
^
cocok dengan awal dan$
akhir baris.(?!)
- pandangan negatif ke arah string kosong. Tetapi beberapa rasa regex akan memperlakukan itu sebagai kesalahan sintaks juga.$^
akan cocok dengan karakter literal tersebut, karena karakter tersebut tidak valid sebagai jangkar (yaitu alasan Anda menggunakan pola yang menyebabkannya tidak melakukan apa yang Anda inginkan.)Yang tercepat adalah:
'a' dapat berupa karakter non-khusus ('x', 'y'). Implementasi Knio mungkin sedikit lebih murni tetapi yang ini akan lebih cepat untuk semua string yang tidak dimulai dengan karakter apa pun yang Anda pilih alih-alih 'a' karena itu tidak akan cocok dengan karakter pertama daripada setelah yang kedua dalam kasus tersebut.
sumber
^
khusus hanya sebagai karakter pertama dan mirip dengan$
. Dengan alat Unix apa pun, regexp itu akan cocok dengan apa pun yang berisi string literala^
.>^
.Python tidak akan menerimanya, tetapi Perl akan:
Regex ini harus (secara teoritis) mencoba untuk mencocokkan jumlah tak terhingga ( datar ) dari
w
s, karena grup pertama (()
s) muncul kembali dengan sendirinya. Perl tampaknya tidak mengeluarkan peringatan apa pun, bahkan di bawahuse strict; use warnings;
, jadi saya menganggap itu setidaknya valid, dan pengujian saya (minimal) gagal mencocokkan apa pun, jadi saya kirimkan untuk kritik Anda.sumber
perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
[^\d\D]
atau(?=a)b
ataua$a
ataua^a
sumber
Ini tidak akan berfungsi untuk Python, dan banyak bahasa lainnya, tetapi dalam regex Javascript,
[]
adalah kelas karakter yang valid yang tidak dapat dicocokkan. Jadi yang berikut ini harus segera gagal, apa pun inputnya:Saya menyukainya lebih baik daripada
/$a/
karena bagi saya, itu jelas menyampaikan maksudnya. Dan ketika Anda membutuhkannya, saya membutuhkannya karena saya membutuhkan cadangan untuk pola yang disusun secara dinamis berdasarkan input pengguna. Ketika polanya tidak valid, saya harus menggantinya dengan pola yang tidak cocok dengan apa pun. Sederhana, terlihat seperti ini:sumber
Semua contoh yang melibatkan pencocokan batas mengikuti resep yang sama. Resep:
Ambil salah satu pencocokan batas: ^, $, \ b, \ A, \ Z, \ z
Bertentangan dengan apa yang dimaksudkan untuk mereka
Contoh:
^ dan \ A dimaksudkan untuk permulaan jadi jangan menggunakannya di awal
\ b cocok dengan batas kata jadi gunakan di antaranya
$, \ Z dan \ z dimaksudkan untuk yang terakhir jadi jangan gunakan pada akhirnya
Lainnya melibatkan penggunaan lookahead dan lookbehind yang juga bekerja dengan analogi yang sama: Jika Anda memberikan lookahead positif atau negatif diikuti oleh sesuatu yang berlawanan
Jika Anda memberikan tampilan positif atau negatif di belakang mengikuti sesuatu yang berlawanan
Mereka bisa lebih seperti pola dan analoginya.
sumber
Begitu banyak jawaban bagus!
Mirip dengan jawaban @ nivk, saya ingin berbagi perbandingan kinerja untuk Perl untuk berbagai varian regex yang tidak pernah cocok.
Kecepatan regex:
Kecepatan regex:
(Ubuntu pada Intel i5-3320M, kernel Linux 4.13, Perl 5.26)
sumber
aku percaya itu
bahkan mencakup kasus-kasus di mana ekspresi reguler termasuk bendera seperti MULTILINE, DOTALL dll.
Saya percaya (tapi saya belum membandingkannya) bahwa berapa pun panjang (> 0) dari string antara
\Z
dan\A
, waktu ke kegagalan harus konstan.sumber
atau
Dengan PCRE dan PERL Anda dapat menggunakan kata kerja kontrol penelusuran ulang ini yang memaksa pola untuk gagal dengan segera.
sumber
Setelah melihat beberapa jawaban hebat ini, komentar @ arantius (mengenai waktu
$x
vsx^
vs(?!x)x
) pada jawaban yang diterima saat ini membuat saya ingin mengatur waktu beberapa solusi yang diberikan sejauh ini.Menggunakan standar garis 275k @ arantius, saya menjalankan tes berikut dengan Python (v3.5.2, IPython 6.2.1).
TL; DR:
'x^'
dan'x\by'
yang tercepat dengan faktor setidaknya ~ 16, dan bertentangan dengan temuan @ arantius,(?!x)x
termasuk yang paling lambat (~ 37 kali lebih lambat). Jadi pertanyaan kecepatan tentu tergantung implementasi. Uji sendiri pada sistem yang Anda inginkan sebelum melakukan apakah kecepatan penting bagi Anda.PEMBARUAN: Rupanya ada perbedaan besar antara waktu
'x^'
dan'a^'
. Silakan lihat pertanyaan ini untuk info lebih lanjut, dan sebelumnya mengedit untuk timing lebih lambat dengana
bukanx
.Pertama kali saya menjalankan ini, saya lupa
r
aw 3 ekspresi terakhir, jadi'\b'
ditafsirkan sebagai'\x08'
, karakter backspace. Namun, yang mengejutkan saya,'a\x08c'
ternyata lebih cepat dari hasil tercepat sebelumnya! Agar adil, itu masih akan cocok dengan teks itu, tapi saya pikir itu masih perlu dicatat karena saya tidak yakin mengapa itu lebih cepat.File pengujian saya dibuat menggunakan rumus untuk "... Konten yang Dapat Dibaca Dan Tidak Ada Garis Duplikat" (di Ubuntu 16.04):
sumber
\B\b
adalah kinerja yang sangat buruk (seperti setiap pola yang tidak berlabuh pada posisi, tetapi pola ini sangat buruk). Coba pembandingan^\B\b
.Regex kosong
Regex terbaik untuk tidak pernah cocok dengan apa pun adalah regex kosong. Tapi saya tidak yakin semua mesin regex akan menerimanya.
Regex yang tidak mungkin
Solusi lainnya adalah membuat regex yang tidak mungkin. Saya menemukan bahwa
$-^
hanya perlu dua langkah untuk menghitung terlepas dari ukuran teks Anda ( https://regex101.com/r/yjcs1Z/1 ).Sebagai referensi:
$^
dan$.
ambil 36 langkah untuk menghitung -> O (1)\b\B
mengambil 1507 langkah pada sampel saya dan meningkat dengan jumlah karakter di string Anda -> O (n)Utas yang lebih populer tentang pertanyaan ini:
sumber
Mungkin ini?
sumber
re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')
mengembalikan objek yang cocok dengan b dan c (dan semua baris baru yang berdekatan dan di antara keduanya). Pendekatan lookahead negatif yang saya sarankan berfungsi (yaitu, gagal mencocokkan apa pun) untuk setiap kombinasi flag yang dapat dikompilasi.$
dan^
./\z.+\A/
(lihat perldoc perlre ) yang mencegah mode multi-line dan single-line (use re '/ms'
) dari memengaruhi itu.dan ganti ... dengan semua simbol yang dapat dicetak;). Itu untuk file teks.
sumber
[^\x00-\xFF]+
(untuk implementasi berbasis byte).[^\s\S]
. Tapi seperti yang sudah dikatakan Ferdinand Beyer, itu akan cocok dengan string kosong.*
; tinggalkan itu, atau ganti dengan+
, dan itu harus cocok dengan setidaknya satu karakter. Jika kelas mengecualikan semua karakter yang mungkin, itu tidak bisa cocok dengan apa pun.Bagaimana dengan alih-alih regex, gunakan saja statemen if false? Dalam javascript:
sumber
Solusi portabel yang tidak akan bergantung pada implementasi regexp adalah dengan hanya menggunakan string konstan yang Anda yakin tidak akan pernah muncul dalam pesan log. Misalnya membuat string berdasarkan pada yang berikut:
Tentu, ini bukan tantangan intelektual, tetapi lebih seperti pemrograman lakban .
sumber
Membuat pola yang hanya berisi alfanumerik dan '
-
' (tidak ada yang merupakan karakter khusus regex) tetapi secara statistik tidak mungkin string yang sama muncul di mana saja sebelumnya (karena itulah inti dari GUID.)sumber