Regex yang tidak akan pernah cocok dengan apa pun


131

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" ...


1
Perhatikan bahwa sangat sulit untuk membuktikan negatif.
Lasse V. Karlsen

5
Menarik. Di mana Anda akan menggunakan regex seperti itu?
Charlie Salts

1
Saya akan mencatat di sini untuk catatan bahwa banyak komentar di atas, dan jawaban atas pertanyaan ini, berasal dari stackoverflow.com/questions/1845078/… yang merupakan salah satu yang saya tanyakan. Marc Gravell menggabungkan mereka, yang saya pikir membuat banyak dari tanggapan ini agak aneh tanpa konteks asli yang tepat, sampai-sampai beberapa komentar tampaknya tidak masuk akal. (Mungkin juga mencuri poin rep potensial di masa depan, juga.) Saya akan menyarankan bahwa pertanyaan dengan latar belakang rinci seperti itu tidak akan pernah bisa menjadi "duplikat yang tepat". Terserah ...
Peter Hansen

2
Pertanyaan ini telah ditambahkan ke FAQ Ekspresi Reguler Overflow Overflow , di bawah "Advanced Regex-Fu".
aliteralmind

3
"Perhatikan bahwa sangat sulit untuk membuktikan negatif" - ini diyakini secara luas namun benar-benar salah ... seperti yang kita ketahui setidaknya sejak Euclid membuktikan bahwa tidak ada prime terbesar. Dan bukti P adalah bukti negasi (bukan P). Yang benar adalah bahwa sulit untuk membuktikan universal empiris, positif atau negatif, misalnya, "semua gagak hitam" atau "tidak ada gagak putih". Algoritma bersifat analitis, bukan empiris, jadi ini adalah penerapan yang salah dari aturan palsu. misalnya, bukti bahwa pola 'a' tidak cocok dengan string apa pun yang dimulai dengan 'b' tidak "sangat sulit".
Jim Balter

Jawaban:


66

Ini sebenarnya cukup sederhana, meskipun tergantung pada implementasi / flag *:

$a

Akan cocok dengan karakter asetelah akhir string. Semoga berhasil.

PERINGATAN:
Ungkapan ini mahal - itu akan memindai seluruh baris, menemukan jangkar end-of-line, dan hanya kemudian tidak menemukan adan 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 seperti atidak pernah bisa muncul setelahnya $.


50
Ungkapan ini mahal - itu akan memindai seluruh baris, menemukan jangkar end-of-line, dan hanya kemudian tidak menemukan "a" dan mengembalikan kecocokan negatif. Saya melihatnya butuh ~ 480ms untuk memindai file baris ~ 275k. Percakapan "a ^" membutuhkan waktu yang sama, bahkan jika itu mungkin tampak lebih efisien. Di sisi lain, lookahead negatif tidak perlu memindai apa pun: "(?! X) x" (apa pun yang tidak diikuti oleh x juga diikuti oleh x, yaitu tidak ada) membutuhkan waktu sekitar 30 ms, atau kurang dari 7% dari waktu. (Diukur dengan waktu gnu dan egrep.)
arantius

1
Di Perl yang akan cocok dengan nilai saat ini dari $a. Ini setara Perl $(?:a)juga sangat lambat perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert

@arantius, silakan lihat jawaban saya mengenai waktu , karena saya menemukan kebalikan yang diukur dengan timeitdan python3.
nivk

Tidak mengejutkan bahwa enam tahun dan versi utama Python dapat mengubah keadaan.
arantius

1
Dalam sintaks POSIX BRE, $aakan cocok dengan teks literal $a, karena $tidak valid sebagai jangkar dalam pola itu.
phils

76

Leverage negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

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:

\A(?!x)x

@ Chris, ya - juga, (?=x)(?!x)dan seterusnya (gabungan dari lookaheads yang bertentangan, dan sama untuk lookbehinds), dan banyak dari mereka juga bekerja untuk nilai-nilai sewenang-wenang x(lookbehinds perlu xs yang cocok dengan string fixed-length).
Alex Martelli

1
Tampaknya bekerja dengan baik. Tapi bagaimana dengan just (?!) Saja? Karena () akan selalu cocok, bukankah (?!) Dijamin tidak akan pernah cocok?
Peter Hansen

2
@ Peter, ya, jika Python menerima sintaks itu (dan rilis terbaru tampaknya), maka itu akan menjadi kontradiksi sendiri juga. Gagasan lain (tidak begitu elegan, tetapi semakin banyak gagasan yang Anda dapatkan, Anda akan menemukan satu yang berfungsi di semua mesin RE yang menarik) r'a\bc':, mencari batas kata yang segera dikelilingi oleh huruf di kedua sisi (varian: karakter non-kata pada kedua sisi).
Alex Martelli

1
Menariknya, sumber asli saya dengan literal sederhana yang saya "tahu" tidak akan muncul di input saya ternyata paling cepat, dengan Python. Dengan string input 5MB, dan menggunakan ini dalam operasi sub (), (?! X) x memakan waktu 21% lebih lama, (?! ()) Adalah 16%, dan ($ ^) 6% lebih lama. Mungkin penting dalam beberapa kasus, meskipun tidak di tambang.
Peter Hansen

2
Itu bisa sangat lambat perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Anda dapat membuatnya lebih cepat dengan menjangkarnya di awal \A(?!x)xatau di akhir (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert

43

Salah satu yang terlewatkan:

^\b$

Itu tidak bisa cocok karena string kosong tidak mengandung batas kata. Diuji dalam Python 2.5.


7
Ini jawaban terbaik. Itu tidak menggunakan lookaheads, tidak istirahat di bawah beberapa implementasi regex, tidak menggunakan karakter tertentu (misalnya 'a'), dan gagal dalam maksimal 3 langkah pemrosesan (menurut regex101.com) tanpa memindai keseluruhan input string. Sekilas ini juga mudah dimengerti.
CubicleSoft

1
Ini sebenarnya gagal di Emacs dalam kondisi tertentu (jika ada baris kosong di awal atau akhir buffer), namun \`\b\'berfungsi, yang menggantikan sintaks Emacs untuk "awal / akhir teks" (sebagai lawan dari "awal / akhir" dari baris ").
phils

35

lihat sekeliling:

(?=a)b

Untuk pemula regex: Tampilan positif di depan (?=a)memastikan bahwa karakter berikutnya adalah a, tetapi tidak mengubah lokasi pencarian (atau menyertakan 'a' dalam string yang cocok). Sekarang karakter berikutnya dikonfirmasikan sebagai a, bagian yang tersisa dari regex ( b) cocok hanya jika karakter berikutnya b. Dengan demikian, regex ini cocok hanya jika karakter adalah baik adan bpada saat yang sama.


30

a\bc, di mana \bekspresi nol-lebar yang cocok dengan batas kata.

Itu tidak dapat muncul di tengah kata, yang kami paksa.


Jika use-case Anda memungkinkan Anda untuk meletakkan pola ke awal string, maka peningkatan itu akan mencegah mesin regexp dari mencari dan menguji setiap instance dari adalam teks.
phils

20

$.

.^

$.^

(?!)


1
Imut! Alam bawah sadar saya menjauhkan saya dari ide-ide seperti tiga, karena mereka "ilegal" ... secara konseptual, tetapi jelas tidak ke regex. Saya tidak mengenali yang (!) ... harus melihat yang itu.
Peter Hansen

1
Baiklah kalau begitu, saya suka jawaban (?!) ... secara efektif apa yang disarankan Alex. Perhatikan bahwa dalam stackoverflow.com/questions/1723182 (ditunjukkan oleh Amarghosh di atas) seseorang mengklaim "rasa" regex akan menganggap bahwa kesalahan sintaksis. Python menyukainya juga. Perhatikan bahwa saran Anda yang lain semuanya akan gagal dengan mode re.DOTALL | re.MULTILINE dalam Python.
Peter Hansen

1
Apakah ini sudah diuji? Saya akan berasumsi bahwa ^hanya memiliki arti khusus sebagai karakter pertama dari regexp, dan $hanya memiliki makna khusus pada akhir regexp, kecuali ekspresi reguler adalah ekspresi multi-line.
PP.

Sebenarnya dalam Perl /$./berarti sesuatu yang sama sekali berbeda. Ini berarti cocok dengan nilai saat ini $.(nomor saluran input) . Bahkan /$(.)/bisa mencocokkan sesuatu jika Anda menulis use re '/s';sebelumnya. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert

Dalam sintaks POSIX BRE, ^dan $hanya khusus pada awal dan akhir (masing-masing) dari pola, sehingga tidak ada $.atau .^atau $.^akan bekerja. (?!)adalah fitur Perl / PCRE, saya percaya.
phils

13

Pencocokan maksimal

a++a

Setidaknya satu adiikuti oleh sejumlah a, tanpa mundur. Kemudian cobalah untuk mencocokkan satu lagi a.

atau sub ekspresi Independen

Ini sama dengan menempatkan a+dalam sub ekspresi independen, diikuti oleh yang lain a.

(?>a+)a

10

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.)


Dokumen untuk itu di perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 mengatakan "Pola ini tidak cocok dan selalu gagal. Ini setara dengan (?!), Tetapi lebih mudah untuk baca. Faktanya, (?!) dioptimalkan menjadi (* GAGAL) secara internal. " Menarik, karena (?!) Adalah jawaban "murni" favorit saya sejauh ini (meskipun tidak bekerja di Javascript). Terima kasih.
Peter Hansen

10
\B\b

\bcocok dengan batas kata - posisi antara huruf dan huruf (atau batas string).
\Badalah pelengkapnya - ini cocok dengan posisi antara dua huruf atau antara non-huruf.

Bersama-sama mereka tidak dapat menandingi posisi apa pun.

Lihat juga:


Ini tampak seperti solusi yang sangat baik, asalkan itu berlabuh ke titik tertentu (awal teks akan tampak masuk akal). Jika Anda tidak melakukannya maka itu adalah solusi yang mengerikan , karena setiap batas non-kata dalam teks akan diuji untuk melihat apakah diikuti oleh batas kata! Jadi versi yang masuk akal akan seperti itu ^\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\batau "\\`\\B\\b".)
phils

Yang mengatakan, saya sekarang mencatat bahwa tujuan yang dinyatakan dari pertanyaan ini adalah untuk mendapatkan regexp untuk digunakan dalam grup, dalam hal ^ini bermasalah dalam sintaksis regexp tertentu (misalnya POSIX BRE) di mana ^hanya jangkar ketika karakter pertama pola, dan jika tidak cocok dengan ^karakter literal .
phils

@ phils - Saya pikir Anda terlalu memikirkannya :)- 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.
Kobi

Optimisasi, saya bersedia mengabaikan mesin regexp yang berharap untuk menemukan "awal teks" di posisi lain :)
phils

Juga, ini bukan T&J yang tidak praktis - satu-satunya alasan saya berakhir di sini adalah untuk melihat apakah ada yang bisa menyarankan solusi yang lebih efisien untuk saya sendiri untuk tujuan praktis mengkonfigurasi variabel Emacs tertentu yang memerlukan nilai regexp, tetapi yang saya ingin menonaktifkan secara efektif.
phils

8

Ini sepertinya berhasil:

$.

2
Itu mirip dengan contoh Ferdinand Beyer.
Gumbo

9
Dan itu akan cocok dengan mode dot-match-newlines.
Tim Pietzcker

Dalam Perl yang benar-benar akan cocok dengan nomor baris input saat ini $.. Dalam hal ini Anda harus menggunakan $(.)atau lebih setara $(?:.).
Brad Gilbert

Dalam sintaks POSIX BRE, $.akan cocok dengan literal $diikuti oleh karakter apa pun, karena $tidak valid sebagai jangkar dalam pola itu.
phils

8

Bagaimana dengan $^atau mungkin (?!)


3
Istirahat baris akan dicocokkan dengan ekspresi ini dalam mode di mana ^cocok dengan awal dan $akhir baris.
Gumbo

4
Mungkin yang dia maksudkan (?!)- pandangan negatif ke arah string kosong. Tetapi beberapa rasa regex akan memperlakukan itu sebagai kesalahan sintaks juga.
Alan Moore

1
String kosong cocok dengan yang pertama, setidaknya dalam JavaScript.
Roland Pihlakas

Dalam sintaks POSIX BRE, $^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.)
phils

5

Yang tercepat adalah:

r = re.compile(r'a^')
r.match('whatever')

'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.


Memang, (. ^) Kira-kira 10% lebih lambat dari (\ x00 ^) dalam kasus saya.
Peter Hansen

1
Saya menerima ini, karena menggunakan nilai apa pun selain \ n sebagai karakter dijamin tidak akan cocok, dan saya melihatnya sedikit lebih mudah dibaca (mengingat bahwa relatif sedikit orang ahli regex) daripada opsi (?! X) x , meskipun saya memilih yang juga. Dalam kasus saya, untuk opsi mana pun saya perlu komentar untuk menjelaskannya, jadi saya pikir saya hanya akan menyesuaikan upaya awal saya untuk '\ x00NEVERMATCHES ^'. Saya mendapatkan jaminan tidak cocok dari jawaban ini, dengan keaslian mendokumentasikan diri saya. Terima kasih untuk semua jawaban!
Peter Hansen

3
Apakah ini benar-benar berhasil dan jika demikian, siapa yang memutuskan untuk memutuskan hubungan dengan Unix? Di Unix regexps, ^khusus hanya sebagai karakter pertama dan mirip dengan $. Dengan alat Unix apa pun, regexp itu akan cocok dengan apa pun yang berisi string literal a^.
JaakkoK

Heh, itu serangan yang bagus. Saya tidak pernah menguji terhadap string literal itu.
Adam Nelson

Oh jika itu merusak Unix regexps, maka Anda akan menyukainya >^.
CubicleSoft

4

Python tidak akan menerimanya, tetapi Perl akan:

perl -ne 'print if /(w\1w)/'

Regex ini harus (secara teoritis) mencoba untuk mencocokkan jumlah tak terhingga ( datar ) dari ws, karena grup pertama ( ()s) muncul kembali dengan sendirinya. Perl tampaknya tidak mengeluarkan peringatan apa pun, bahkan di bawah use strict; use warnings;, jadi saya menganggap itu setidaknya valid, dan pengujian saya (minimal) gagal mencocokkan apa pun, jadi saya kirimkan untuk kritik Anda.


1
Teori selalu baik, tetapi dalam praktiknya saya pikir saya akan khawatir tentang ekspresi reguler yang uraiannya termasuk kata "tak terbatas"!
Peter Hansen

perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Brad Gilbert

@BradGilbert - Menjalankannya di sini (5.10, sedikit ketinggalan zaman) menghasilkan "regex gagal", seperti yang diminta OP. Apakah cocok dengan sistem Anda?
Chris Lutz

4

[^\d\D]atau (?=a)batau a$aataua^a


Terima kasih. Perhatikan bahwa (?! X) x adalah jawaban pertama yang diberikan, tercantum di atas.
Peter Hansen

Ya, sepertinya saya memindai penjawab lain terlalu cepat.
Bart Kiers

4

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:

var noMatch = /^[]/;

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:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}

4

Semua contoh yang melibatkan pencocokan batas mengikuti resep yang sama. Resep:

  1. Ambil salah satu pencocokan batas: ^, $, \ b, \ A, \ Z, \ z

  2. Bertentangan dengan apa yang dimaksudkan untuk mereka

Contoh:

^ dan \ A dimaksudkan untuk permulaan jadi jangan menggunakannya di awal

^ --> .^
\A --> .\A

\ b cocok dengan batas kata jadi gunakan di antaranya

\b --> .\b.

$, \ Z dan \ z dimaksudkan untuk yang terakhir jadi jangan gunakan pada akhirnya

$ --> $.
\Z --> \Z.
\z --> \z.

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

(?=x)[^x]
(?!x)x

Jika Anda memberikan tampilan positif atau negatif di belakang mengikuti sesuatu yang berlawanan

[^x](?<=x)
x(?<!x)

Mereka bisa lebih seperti pola dan analoginya.


3

Begitu banyak jawaban bagus!

Mirip dengan jawaban @ nivk, saya ingin berbagi perbandingan kinerja untuk Perl untuk berbagai varian regex yang tidak pernah cocok.

  1. Input: string ascii pseudo-acak (25.000 baris berbeda, panjang 8-16):

Kecepatan regex:

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
  1. Input: / usr / share / dikt / kata (100.000 kata bahasa Inggris).

Kecepatan regex:

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s

(Ubuntu pada Intel i5-3320M, kernel Linux 4.13, Perl 5.26)


Berikut adalah perbandingan JavaScript dari beberapa metode yang dibahas di sini: jsperf.com/regex-that-never-matches
thdoan

2

aku percaya itu

\Z RE FAILS! \A

bahkan mencakup kasus-kasus di mana ekspresi reguler termasuk bendera seperti MULTILINE, DOTALL dll.

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

Saya percaya (tapi saya belum membandingkannya) bahwa berapa pun panjang (> 0) dari string antara \Zdan \A, waktu ke kegagalan harus konstan.


2
(*FAIL)

atau

(*F)

Dengan PCRE dan PERL Anda dapat menggunakan kata kerja kontrol penelusuran ulang ini yang memaksa pola untuk gagal dengan segera.


2

Setelah melihat beberapa jawaban hebat ini, komentar @ arantius (mengenai waktu $xvs x^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)xtermasuk 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 dengan abukan x.

In [1]: import re

In [2]: with open('/tmp/longfile.txt') as f:
   ...:     longfile = f.read()
   ...:     

In [3]: len(re.findall('\n',longfile))
Out[3]: 275000

In [4]: len(longfile)
Out[4]: 24733175

In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
    ...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
    ...:     print('-'*72)
    ...:     print(regex)
    ...:     %timeit re.search(regex,longfile)
    ...:     
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

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.

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
    ...:     print('-'*72)
    ...:     print(regex, repr(regex))
    ...:     %timeit re.search(regex,longfile)
    ...:     print(re.search(regex,longfile))
    ...:     
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

File pengujian saya dibuat menggunakan rumus untuk "... Konten yang Dapat Dibaca Dan Tidak Ada Garis Duplikat" (di Ubuntu 16.04):

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt

$ head -n5 /tmp/longfile.txt 
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe

\B\badalah kinerja yang sangat buruk (seperti setiap pola yang tidak berlabuh pada posisi, tetapi pola ini sangat buruk). Coba pembandingan ^\B\b.
phils

2

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:


1

Mungkin ini?

/$.+^/

Dalam Python, pendekatan ini hanya berfungsi jika Anda mengontrol flag : 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.
Alex Martelli

Buruk saya - mencampuradukkan $dan ^.
Chris Lutz

1
Ini mungkin merupakan upaya untuk mencari akhir string sebelum awal, tetapi saya telah menemukan bahwa $ tidak berarti 'akhir string' kecuali itu adalah karakter terakhir dari regex, dan saya berharap perilaku serupa berlaku untuk ^, jadi ini mungkin cocok dengan substring dimulai dengan $ literal, dan berakhir dengan literal ^
pavium

@ Pavium, tentu saja tidak berperilaku seperti itu dalam Python atau Javascript. Kecuali jika Anda menghindarinya dengan \ atau memasukkannya ke dalam rangkaian karakter dengan [], karakter khusus seperti $ dan ^ tidak boleh diperlakukan sebagai literal. Dalam bahasa apa Anda mengamati ini?
Peter Hansen

Dalam Perl, setidaknya, itu harus ditulis /\z.+\A/(lihat perldoc perlre ) yang mencegah mode multi-line dan single-line ( use re '/ms') dari memengaruhi itu.
Brad Gilbert

0
'[^0-9a-zA-Z...]*'

dan ganti ... dengan semua simbol yang dapat dicetak;). Itu untuk file teks.


Saya pikir harus ada cara yang lebih pendek untuk itu, tetapi itu adalah pemikiran pertama saya juga ^^
FP

4
Ini akan cocok dengan string kosong. Untuk menangkap setiap karakter yang mungkin, gunakan [^\x00-\xFF]+(untuk implementasi berbasis byte).
Ferdinand Beyer

6
Ekspresi yang lebih baik adalah [^\s\S]. Tapi seperti yang sudah dikatakan Ferdinand Beyer, itu akan cocok dengan string kosong.
Gumbo

3
Regex Drakosha dapat mencocokkan string kosong karena *; 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.
Alan Moore

0

Bagaimana dengan alih-alih regex, gunakan saja statemen if false? Dalam javascript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}

Saya menambahkan komentar untuk menjawab pertanyaan Charlie, menjelaskan mengapa pendekatan semacam ini tidak diinginkan. Singkatnya, saya memerlukan grup di dalam regex yang akan selalu digunakan, tetapi dalam beberapa kasus grup harus dibangun untuk memastikannya tidak pernah cocok.
Peter Hansen

-2

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:

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

Tentu, ini bukan tantangan intelektual, tetapi lebih seperti pemrograman lakban .


-6
new Regex(Guid.NewGuid().ToString())

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.)


2
"Secara statistik tidak mungkin"? Hah? Bergantung pada bagaimana GUID dihitung, adalah mungkin dan seringkali cukup sederhana untuk memprediksi GUID berikutnya (karena mereka bergantung pada mesin yang menghitungnya dan waktu). Maksud Anda "tidak mungkin", "dengan probabilitas yang sangat kecil", tetapi Anda tidak bisa mengatakan "tidak mungkin" bahkan untuk string acak sempurna. Regex Anda akan cocok dengan jumlah string yang tidak terbatas - pertanyaan ini mencari yang tidak cocok dengan apa pun. Pernah.
Ferdinand Beyer
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.