Asla hiçbir şeyle eşleşmeyecek bir Regex


131

Bu aptalca bir soru gibi gelebilir, ancak bazı geliştiricilerimle uzun bir konuşma yaptım ve düşünmesi eğlenceli bir şey gibi geldi.

Yani; ne düşünüyorsun - bir Regex neye benziyor, bu asla hiçbir dizeyle eşleşmeyecek!

Düzenleme : Bunu neden istiyorum? Öncelikle böyle bir ifadeyi düşünmeyi ilginç bulduğum için ve ikinci olarak da bir senaryo için ona ihtiyacım olduğu için.

Bu senaryoda bir sözlüğü olarak tanımlıyorum Dictionary<string, Regex>. Bu, gördüğünüz gibi, bir dizgi ve bir ifade içerir.

Bu sözlüğe dayanarak, bu sözlüğü yalnızca işlerini nasıl yapmaları gerektiğine dair referans olarak kullanan yöntemler oluşturuyorum, bunlardan biri regex'leri ayrıştırılmış bir günlük dosyasıyla eşleştiriyor.

Bir ifade eşleşirse, başka bir ifade Dictionary<string, long>tarafından döndürülen bir değer eklenir. Bu yüzden, sözlükteki bir ifadeyle eşleşmeyen günlük mesajlarını yakalamak için "bilinmeyen" adlı yeni bir grup oluşturdum.

Bu gruba başka hiçbir şeyle eşleşmeyen her şey eklenir. Ancak "bilinmeyen" ifadesinin bir günlük mesajıyla eşleşmemesini (kazara) önlemek için, hangi dizeyi verirsem vereyim, kesinlikle hiçbir zaman eşleşmeyen bir ifade oluşturmam gerekiyordu.

İşte bu "gerçek bir soru değil" için nedenim var ...


1
Negatif olduğunu kanıtlamanın çok zor olduğunu unutmayın.
Lasse V. Karlsen

5
İlginç. Böyle bir normal ifadeyi nerede kullanırsınız?
Charlie Salts

1
Buraya, yukarıdaki yorumların ve bu soruya verilen yanıtların çoğunun , sorduğum gibi stackoverflow.com/questions/1845078/… adresinden geldiğini not edeceğim. Marc Gravell bunları birleştirdi, ki bence bu yanıtların çoğunu orijinal bağlam olmadan biraz tuhaf kılıyor, bazı yorumların mantıklı görünmediği noktaya. (Muhtemelen gelecekteki potansiyel tekrar noktalarını da ortadan kaldırır.) Bu kadar detaylı geçmişe sahip soruların asla "tam olarak aynı" olamayacağını öneririm. Her neyse ...
Peter Hansen

2
Bu soru, "Gelişmiş Regex-Fu" altındaki Yığın Taşması Normal İfadeler SSS bölümüne eklenmiştir .
aliteralmind

3
"Negatifi ispatlamanın çok zor olduğuna dikkat edin" - bu yaygın bir şekilde inanılıyor, ancak tamamen ve açık bir şekilde yanlış ... Ve P'nin herhangi bir kanıtı, (P'nin değil) olumsuzlamasının bir kanıtıdır. Doğru olan, ampirik bir evrensel, olumlu veya olumsuz, örneğin "tüm kuzgunlar siyahtır" veya "hiçbir kuzgun beyaz değildir" ispatlamanın zordur. Algoritmalar analitiktir, deneysel değildir, bu nedenle bu, sahte kuralın özellikle kötü bir yanlış uygulamasıdır. Örneğin, 'a' kalıbının 'b' ile başlayan herhangi bir dizeyle eşleşmediğinin ispatı "çok zor" değildir.
Jim Balter

Yanıtlar:


66

Gerçekleştirmeye / bayraklara * bağlı olmasına rağmen bu aslında oldukça basittir :

$a

aDizenin sonundan sonraki karakterle eşleşir . İyi şanslar.

UYARI:
Bu ifade pahalıdır - tüm satırı tarayacak, satır sonu bağlantısını bulacak ve ancak o zaman bulup anegatif bir eşleşme döndürmeyecektir. (Daha fazla ayrıntı için aşağıdaki yoruma bakın.)


* Başlangıçta $, bir satırın sonuyla da eşleştiği çok satırlı regexp üzerine fazla düşünmedim . Aslında, satırsonunun hemen önündeki boş dizeyle eşleşir , bu nedenle gibi sıradan bir karakter aasla sonra görünemez $.


50
Bu ifade pahalıdır - tüm satırı tarayacak, satır sonu bağlantısını bulacak ve ancak o zaman "a" yı bulamayacak ve negatif bir eşleşme döndürecektir. Bir ~ 275k satır dosyasını taramanın ~ 480ms sürdüğünü görüyorum. "A ^" tersi, daha verimli görünse bile yaklaşık aynı süreyi alır. Öte yandan, negatif bir önden okuma hiçbir şeyi taramak zorunda değildir: "(?! X) x" (bir x'in ardından bir x gelmeyen herhangi bir şey, yani hiçbir şey) yaklaşık 30 ms veya zamanın% 7'sinden az sürer. (Gnu zamanı ve egrep ile ölçülmüştür.)
arantius

1
Perl'de şu anki değer ile eşleşecek $a. Perl eşdeğeri $(?:a)de çok yavaştır perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert

@arantius, ve ile ölçülen tam tersini bulduğum için lütfen zamanlama ile ilgili cevabıma bakın . timeitpython3
nivk

Altı yılın ve Python'un büyük bir sürümünün bir şeyleri değiştirmesi şaşırtıcı değil.
arantius

1
POSIX BRE sözdiziminde, $adeğişmez metinle eşleşir $a, çünkü $bu modelde çapa olarak geçersizdir.
phils

76

Kaldıraç negative lookahead:

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

bu RE, terimler açısından bir çelişkidir ve bu nedenle asla hiçbir şeyle eşleşmeyecektir.

NOT:
Python'da, re.match () örtük \Aolarak normal ifadenin başlangıcına bir dize başlangıcı çapa ( ) ekler . Bu çapa performans için önemlidir: onsuz, tüm dizi taranacaktır. Python kullanmayanlar, çapayı açıkça eklemek isteyeceklerdir:

\A(?!x)x

@Chris, evet - ayrıca, (?=x)(?!x)vb. ( Birbiriyle çelişen bakış açılarının birleştirilmesi ve arkaya bakma için aynı) ve bunların çoğu aynı zamanda keyfi değerleri için de çalışır x(lookbehinds xsabit uzunluktaki dizelerle eşleşen s gerekir ).
Alex Martelli

1
İyi çalışıyor gibi görünüyor. Peki ya bunun yerine sadece (?!)? () Her zaman eşleşeceğinden (?!) Asla eşleşmeyeceği garanti edilmez mi?
Peter Hansen

2
@Peter, evet, eğer Python bu sözdizimini kabul ederse (ve son sürümler böyle görünürse), o zaman kendi kendine çelişir. Başka bir fikir (o kadar zarif değil, ama ne kadar çok fikir edinirseniz, ilgilendiğiniz tüm RE motorlarında çalışan bir tane bulma olasılığınız r'a\bc'artar):, hemen her iki tarafı harflerle çevrili bir kelime sınırı aramak (varyant: üzerinde sözcük olmayan karakterler) İki taraf da).
Alex Martelli

1
İlginç bir şekilde, girdimde görünmeyeceğini "bildiğim" basit bir harfli orijinalim Python'da en hızlı çıktı. 5 MB'lık bir girdi dizesi ile ve bunu bir alt () işleminde kullanarak, (?! X) x% 21 daha uzun, (?! ())% 16 ve ($ ^)% 6 daha uzun sürer. Benimkinde olmasa da bazı durumlarda önemli olabilir.
Peter Hansen

2
Bu oldukça yavaş olabilir perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Başlangıçta \A(?!x)xveya sonunda sabitleyerek daha hızlı hale getirebilirsiniz (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert

43

Kaçırılanlardan biri:

^\b$

Boş dize bir kelime sınırı içermediğinden eşleşemez. Python 2.5'te test edilmiştir.


7
Bu en iyi cevap. Önden okuma kullanmaz, bazı düzenli ifade uygulamalarının altında kırılmaz, belirli bir karakter (örneğin 'a') kullanmaz ve tümünü taramadan maksimum 3 işlem adımında (regex101.com'a göre) başarısız olur. girdi dizesi. Bunu bir bakışta anlamak da kolaydır.
CubicleSoft

1
Bu aslında Emacs'de belirli koşullarda başarısız olur (arabelleğin başlangıcında veya sonunda boş bir satır varsa), ancak \`\b\'çalışır, bu da "metnin başlangıcı / sonu" yerine Emacs sözdizimini değiştirir ("başlangıç ​​/ bitiş" yerine hattının").
phils

35

etrafa bak:

(?=a)b

Normal ifade yeni başlayanlar için: İleriye dönük olumlu bakış (?=a), sonraki karakterin olmasını sağlar a, ancak arama konumunu değiştirmez (veya eşleşen dizeye 'a' harfini dahil etmez). Artık bir sonraki karakter olduğu onaylandığına agöre, regex ( b) ' in kalan kısmı yalnızca bir sonraki karakter ise eşleşir b. Böylece, bu regex bir karakter hem yalnızca maçları ave baynı anda.


30

a\bc, \bkelime sınırıyla eşleşen sıfır genişlikli bir ifade nerede .

Onu zorladığımız bir kelimenin ortasında görünemez.


Kullanım durumunuz, kalıbı dizenin başlangıcına sabitlemenize izin veriyorsa, bu geliştirme, regexp motorunun bir dizenin her örneğini aramasını ve test etmesini önleyecektir. a metindeki .
phils

20

$.

.^

$.^

(?!)


1
Şirin! Bilinçaltım beni ilk üç gibi fikirlerden uzaklaştırdı, çünkü bunlar kavramsal olarak "yasadışı" ... ama belli ki normal ifade için değil. (!) Birini tanımıyorum ... buna bakmak zorunda kalacak.
Peter Hansen

1
Tamam o zaman, Alex'in önerdiği (?!) Cevabını beğendim ... etkili bir şekilde. O Not stackoverflow.com/questions/1723182 (yukarıda Amarghosh tarafından işaret) birisi iddiaları regex ait "Bazı tatlar" bir sözdizimi hatası olduğunu ele alacak. Python yine de hoşuna gidiyor. Diğer önerilerinizin Python'da re.DOTALL | re.MULTILINE modları ile başarısız olacağını unutmayın.
Peter Hansen

1
Bu test edildi mi? Normal ifadenin çok satırlı bir ifade olmadığı sürece, bir normal ifadenin yalnızca ^ilk karakteri olarak özel bir anlama sahip olduğunu ve $yalnızca bir normal ifadenin sonunda özel bir anlama sahip olduğunu varsayardım .
PP.

Aslında Perl'de /$./tamamen farklı bir şey ifade eder. $.(Giriş satırı numarası) ' nın mevcut değeriyle eşleştiği anlamına gelir . Daha önce yazsanız bile bir /$(.)/şey eşleşebilir use re '/s';. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert

POSIX BRE sözdiziminde, ^ve $, desen başında ve (sırasıyla) sonunda sadece özeldir hiçbiri bu kadar $.ya .^ya $.^çalışacak. (?!)bir Perl / PCRE özelliği olduğuna inanıyorum.
phils

13

Maksimum eşleme

a++a

Geriye dönmeden en az bir tanesi aherhangi bir sayıda a'nın izlediği . Sonra bir tane daha eşleştirmeye çalışın a.

veya Bağımsız alt ifade

Bu, a+bağımsız bir alt ifade ve ardından başka bir ifade koymaya eşdeğerdir a.

(?>a+)a

10

Perl 5.10, (*...)sırayla eklenen "fiiller" adlı özel kontrol kelimelerini destekler . ( (?...)Özel sıra ile karşılaştırın .) Bunların arasında şunları içerir:(*FAIL) fiil , normal ifadeden hemen dönen .

Fiillerin kısa bir süre sonra PCRE'de de uygulandığına dikkat edin, böylece bunları PHP'de veya PCRE kitaplığını kullanarak diğer dillerde de kullanabilirsiniz. (Python veya Ruby'de yapamazsınız. Kendi motorlarını kullanırlar.)


Perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 adresindeki bununla ilgili dokümanlar "Bu kalıp hiçbir şeyle eşleşmez ve her zaman başarısız olur. (?!) İle eşdeğerdir, ancak Aslında, (?!) dahili olarak (* BAŞARISIZ) olarak optimize edilir. " İlginç, çünkü (?!) Şimdiye kadarki en sevdiğim "saf" cevap (Javascript'te çalışmasa da). Teşekkürler.
Peter Hansen

10
\B\b

\b kelime sınırlarıyla eşleşir - bir harf ile harf olmayan arasındaki konum (veya dize sınırı).
\Bonun tamamlayıcısıdır - iki harf arasındaki veya harf olmayanlar arasındaki konumla eşleşir.

Birlikte herhangi bir pozisyonla eşleşemezler.

Ayrıca bakınız:


Bu, belirli bir noktaya bağlı olması koşuluyla (metnin başlangıcı mantıklı görünür) mükemmel bir çözüm gibi görünüyor. Bunu yapmazsanız, bu korkunç bir çözümdür, çünkü metindeki sözcük olmayan her sınırın ardından bir sözcük sınırı gelip gelmediğini görmek için test edilecektir! Yani mantıklı versiyon şöyle bir şey olurdu ^\B\b. "Metnin başlangıcı" ve "satır başlangıcı" nın farklı sözdizimine sahip olduğu dillerde, "metnin başlangıcı" sözdizimini kullanmak istersiniz, aksi takdirde her satırı test edersiniz. (örneğin \`\B\b"\\`\\B\\b"
Emacs'ta

Bununla birlikte, şimdi bu sorunun belirtilen amacının bir grupta kullanılmak üzere bir normal ifade elde etmek olduğunu belirttim; bu durumda ^, belirli normal ifade sözdiziminde (örneğin, POSIX BRE) ^yalnızca ilk karakter olduğunda bir çapa olan sorunludur. kalıbın ve aksi takdirde değişmez bir ^karakterle eşleşir .
phils

@phils - Bence fazla düşünüyorsunuz :)- bu pratik olmayan bir soru, burada amacın ilginç bir cevap bulmak olduğu - etkili bir cevap değil. Bununla birlikte, desen, astar zamanında reddedilebilir (hedef dizenin boyutuyla birlikte), bu nedenle bir normal ifade için kötü değildir - buradaki çoğu desen aynıdır ve hatta ^optimize edilmemişse doğrusal olabilir.
Kobi

Re: optimizasyonlar, başka herhangi bir konumda "metnin başlangıcını" bulmayı uman bir regexp motorunu görmezden gelmeye hazırım :)
phils

Ayrıca, bu o kadar da pratik olmayan bir Soru-Cevap değil - buraya gelmemin tek nedeni , bir regexp değeri gerektiren belirli bir Emacs değişkenini yapılandırmak gibi pratik bir amaç için birinin benim için daha verimli bir çözüm önerip öneremeyeceğini görmekti, ancak benim etkili bir şekilde devre dışı bırakmak istedi.
phils

8

Bu işe yarıyor gibi görünüyor:

$.

2
Bu Ferdinand Beyer'in örneğine benzer.
Gumbo

9
Ve nokta-eşleşme-satırsonu modunda eşleşecektir.
Tim Pietzcker

Perl'de, mevcut giriş satır numarasıyla gerçekten eşleşecek $.. Bu durumda, $(.)veya daha eşit bir şekilde başvurmanız gerekir $(?:.).
Brad Gilbert

POSIX BRE sözdiziminde, herhangi bir karakterin izlediği $.değişmez bir değerle eşleşir $, çünkü $bu desende bir çapa olarak geçersizdir.
phils

8

Nasıl hakkında $^ya da belki (?!)


3
Bir satır sonu modunda bu ifadesinin eşleştiği edilecek ^maçları başlayacak ve $bir satırın sonunda.
Gumbo

4
Belki de kastetti (?!)- boş bir dizeye olumsuz bir bakış. Ancak bazı normal ifade çeşitleri bunu da bir sözdizimi hatası olarak ele alır.
Alan Moore

1
Boş bir dize, en azından JavaScript'te ilkiyle eşleşir.
Roland Pihlakas

POSIX BRE sözdiziminde, $^bu değişmez karakterlerle eşleşir, çünkü karakterler çapa olarak geçersizdir (yani, kalıbı kullanmanızın nedeni sizin istediğiniz şeyi yapmamasına neden olur)
phils

5

En hızlısı:

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

'a' özel olmayan herhangi bir karakter ('x', 'y') olabilir. Knio'nun uygulaması biraz daha saf olabilir, ancak bu, 'a' yerine seçtiğiniz karakterle başlamayan tüm dizeler için daha hızlı olacaktır çünkü bu durumlarda ikinci karakterden sonra değil ilk karakterden sonra eşleşmeyecektir.


Aslında, (. ^) Benim durumumda (\ x00 ^) 'den kabaca% 10 daha yavaş olurdu.
Peter Hansen

1
Bunu kabul ediyorum, çünkü karakterin hiçbir zaman eşleşmeyeceği garanti edildiğinden \ n dışında herhangi bir değer kullanmak ve bunu (?! X) x seçeneğinden biraz daha okunaklı buluyorum (nispeten az kişinin normal ifade uzmanı olduğu göz önüne alındığında) ama buna ben de oy verdim. Benim durumumda, her iki seçenek için de onu açıklamak için bir yoruma ihtiyacım olacak, bu yüzden orijinal denememi '\ x00NEVERMATCHES ^' olarak ayarlayacağımı düşünüyorum. Kendi orijinal belgemle bu cevabın eşleşmeme garantisini alıyorum. Cevaplar için herkese teşekkürler!
Peter Hansen

3
Bu gerçekten işe yarıyor mu ve eğer öyleyse, kim Unix'ten ayrılmaya karar verdi? Unix regexps'de, ^yalnızca ilk karakter olarak özeldir ve $. Herhangi bir Unix aracıyla, bu regexp değişmez dizeyi içeren herhangi bir şeyle eşleşecektir a^.
JaakkoK

Heh, bu iyi bir saldırı. Bu gerçek diziye karşı asla test etmedim.
Adam Nelson

Bu, Unix regexp'lerini bozarsa, seveceksiniz >^.
CubicleSoft

4

Python bunu kabul etmeyecek, ancak Perl şunları yapacak:

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

Bu normal ifade (teorik olarak) sonsuz (çift) sayıda ws ile eşleşmeye çalışmalıdır , çünkü ilk grup ( ()lar) kendi içinde tekrar eder. Perl, altında bile herhangi bir uyarı veriyor gibi görünmüyor use strict; use warnings;, bu yüzden en azından geçerli olduğunu ve (minimal) testimin hiçbir şeyle eşleşmediğini varsayıyorum, bu yüzden eleştiriniz için gönderiyorum.


1
Teori her zaman iyidir, ancak pratikte açıklamaları "sonsuz" kelimesini içeren normal ifadeler için endişeleneceğimi düşünüyorum!
Peter Hansen

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

@BradGilbert - Bunu burada çalıştırmak (5.10, biraz eski), OP'nin talep ettiği gibi "normal ifade başarısız" üretir. Sisteminizle eşleşiyor mu?
Chris Lutz

4

[^\d\D]veya (?=a)bveya a$aveyaa^a


Teşekkürler. Yukarıda listelenen ilk yanıtın (?! X) x olduğuna dikkat edin.
Peter Hansen

Evet, diğer cevaplayıcıları çok hızlı taradım.
Bart Kiers

4

Bu Python ve diğer birçok dilde işe yaramaz, ancak bir Javascript normal ifadesinde []eşleştirilemeyen geçerli bir karakter sınıfıdır. Dolayısıyla, giriş ne olursa olsun aşağıdakiler hemen başarısız olmalıdır:

var noMatch = /^[]/;

Bunu daha çok seviyorum /$a/çünkü bana göre amacını açıkça ifade ediyor. Ve ne zaman ihtiyaç duyacağınıza gelince, buna ihtiyacım vardı çünkü kullanıcı girdisine dayalı dinamik olarak derlenmiş bir model için bir yedeğe ihtiyacım vardı. Kalıp geçersiz olduğunda, hiçbir şeyle eşleşmeyen bir kalıpla değiştirmem gerekir. Basitleştirilmiş, şuna benzer:

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

4

Bir sınır eşleştirici içeren tüm örnekler aynı tarifi izler. Yemek tarifi:

  1. Sınır eşleştiricilerden herhangi birini alın: ^, $, \ b, \ A, \ Z, \ z

  2. Onların amacının tersini yapın

Örnekler:

^ ve \ A başlangıç ​​içindir, bu yüzden başlangıçta kullanmayın

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

\ b bir kelime sınırıyla eşleşir, bu yüzden arada kullanın

\b --> .\b.

$, \ Z ve \ z amaç içindir, bu yüzden onları sonunda kullanmayın

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

Diğerleri de aynı benzetme ile çalışan önden bakma ve arkaya bakma kullanımını içerir: Olumlu veya olumsuz önden bakış ve ardından karşıt bir şey verirseniz

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

Tersini takip ederek arkasına olumlu veya olumsuz bakarsan

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

Daha çok böyle kalıp ve daha çok benzetmeler olabilir.


3

Çok fazla iyi cevap!

@ Nivk'in cevabına benzer şekilde, asla eşleşmeyen normal ifadenin farklı varyantları için Perl için performans karşılaştırmasını paylaşmak istiyorum.

  1. Giriş: sözde rastgele ascii dizeleri (25.000 farklı satır, uzunluk 8-16):

Normal ifade hızı:

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. Giriş: / usr / share / dict / words (100.000 İngilizce kelime).

Normal ifade hızı:

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

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


Burada ele alınan bazı yöntemlerin JavaScript karşılaştırması: jsperf.com/regex-that-never-matches
thdoan

2

buna inanıyorum

\Z RE FAILS! \A

normal ifadenin MULTILINE, DOTALL vb. bayrakları içerdiği durumları bile kapsar

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

İnanıyorum (ama bunu benchmarked değil) arasındaki dizenin ne olursa olsun uzunluğu (> 0) olduğu \Zve \A, süre-başarısızlık sabit olmalıdır.


2
(*FAIL)

veya

(*F)

PCRE ve PERL ile, kalıbı anında başarısız olmaya zorlayan bu geri izleme kontrol fiilini kullanabilirsiniz.


2

Bu harika yanıtlardan bazılarını gördükten sonra, @ arantius'un yorumu (zamanlama $xile x^vs(?!x)x şu anda kabul edilen cevapla ) şimdiye kadar verilen çözümlerin bazılarını istememe neden oldu.

@ Arantius'un 275k satır standardını kullanarak aşağıdaki testleri Python'da (v3.5.2, IPython 6.2.1) çalıştırdım.

TL; DR: 'x^'ve 'x\by'en az ~ 16 faktör ile en hızlı olanlardır ve @ arantius'un bulgusunun tersine (?!x)x, en yavaşlar (~ 37 kat daha yavaş). Dolayısıyla hız sorusu kesinlikle uygulamaya bağlıdır. Hız sizin için önemliyse, taahhütte bulunmadan önce amaçladığınız sistemde kendiniz test edin.

GÜNCELLEME: Görünüşe göre zamanlama 'x^'ve 'a^'. Lütfen daha fazla bilgi için bu soruya ve ayerine ile daha yavaş zamanlamalar için önceki düzenlemeye bakın 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)

Bunu ilk çalıştırdığımda r, son 3 ifadeyi unutmayı unuttum , bu yüzden geri boşluk karakteri '\b'olarak yorumlandı '\x08'. Ancak, beni şaşırtacak şekilde, 'a\x08c'önceki en hızlı sonuçtan daha hızlıydı! Adil olmak gerekirse, yine de bu metinle eşleşecek, ancak yine de kayda değer olduğunu düşündüm çünkü neden daha hızlı olduğundan emin değilim.

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

Test dosyam "... Okunabilir İçerik ve Yinelenen Satır Yok" formülü kullanılarak oluşturuldu (Ubuntu 16.04'te):

$ 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\bperformans açısından korkunç derecede kusurludur (bir konuma bağlı olmayan her model gibi, ancak bu model özellikle kötüdür). ^\B\bBunun yerine karşılaştırmayı deneyin .
phils

2

Boş normal ifade

Hiçbir zaman eşleşmeyen en iyi normal ifade boş bir normal ifadedir. Ancak tüm normal ifade motorunun bunu kabul edeceğinden emin değilim.

İmkansız normal ifade

Diğer çözüm ise imkansız bir normal ifade oluşturmaktır. $-^Metninizin boyutundan bağımsız olarak hesaplamanın yalnızca iki adımda gerçekleştiğini buldum ( https://regex101.com/r/yjcs1Z/1 ).

Referans için:

  • $^ ve $. hesaplamak için 36 adım atın -> O (1)
  • \b\B Örneğimde 1507 adım atıyor ve dizenizdeki karakter sayısı ile artıyor -> O (n)

Bu soru hakkında daha popüler konu:


1

Belki bu?

/$.+^/

Python'da, bu yaklaşım yalnızca bayrakları kontrol ederseniz işe yarar : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')b ve c'ye karşılık gelen bir eşleşme nesnesi döndürür (ve tüm bitişik ve ara satırlar). Negatif önden okuma yaklaşımı, derlenebileceği bayrakların herhangi bir kombinasyonu için çalışır (yani hiçbir şeyi eşleştiremez).
Alex Martelli

Benim kötü - karışık $ve ^.
Chris Lutz

1
Bu , başlangıçtan önce bir dizenin sonunu arama girişimi olabilir , ancak $ 'ın normal ifadenin son karakteri olmadığı sürece' dizenin sonu 'anlamına gelmediğini buldum ve benzer bir davranışın geçerli olmasını bekliyorum için ^, yani bu, değişmez $ ile başlayan ve değişmez ^
pavium

@pavium, Python veya Javascript'te kesinlikle bu şekilde davranmaz. Onlardan \ ile çıkış yapmadığınız veya [] ile bir karakter kümesine dahil etmediğiniz sürece, $ ve ^ gibi özel karakterler değişmez değer olarak değerlendirilmemelidir. Bunu hangi dilde gözlemlediniz?
Peter Hansen

En azından Perl'de bu yazılmalıdır /\z.+\A/( perldoc perlre'ye bakın ) Bu, çok satırlı ve tek satırlı modun ( use re '/ms') onu etkilemesini engeller .
Brad Gilbert

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

ve ... tüm yazdırılabilir sembollerle değiştirin;). Bu bir metin dosyası için.


Sanırım bunun daha kısa bir yolu olmalı, ama benim de ilk düşüncem buydu ^^
FP

4
Bu, boş dizeyle eşleşecek. Olası her karakteri yakalamak için [^\x00-\xFF]+(bayt tabanlı uygulamalar için) kullanın.
Ferdinand Beyer

6
Daha iyi bir ifade olur [^\s\S]. Ancak Ferdinand Beyer'in daha önce de söylediği gibi boş bir dizeyle eşleşirdi.
Gumbo

3
Drakosha'nın normal ifadesi *; nedeniyle boş bir dizeyle eşleşebilir ; bunu kapalı bırakın veya ile değiştirin +ve en az bir karakterle eşleşmelidir. Sınıf olası tüm karakterleri hariç tutarsa ​​hiçbir şeyle eşleşemez.
Alan Moore

0

Normal ifade yerine her zaman yanlış if ifadesi kullanın. JavaScript'te:

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

Charlie'nin sorusuna yanıt olarak, bu tür bir yaklaşımın neden istenmediğini açıklayan bir yorum ekledim. Kısacası, bir normal ifadenin içinde her zaman kullanılacak bir gruba ihtiyacım var, ancak bazı durumlarda grubun asla eşleşemeyeceğinden emin olmak için oluşturulması gerekir.
Peter Hansen

-2

Regexp uygulamasına bağlı olmayacak taşınabilir bir çözüm, yalnızca günlük mesajlarında asla görünmeyeceğinden emin olduğunuz sabit bir dizeyi kullanmaktır. Örneğin, aşağıdakilere göre bir dizge oluşturun:

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

Elbette, bu entelektüel bir zorluk değil, daha çok koli bandı programlamaya benziyor .


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

Yalnızca alfanümerik ve ' -' (hiçbiri normal ifade özel karakterleri değildir) içeren bir kalıp oluşturur, ancak aynı dizenin daha önce herhangi bir yerde görünmesi istatistiksel olarak imkansızdır (çünkü bu, bir GUID'in tüm noktasıdır.)


2
İstatistiksel olarak imkansız mı? Ha? GUID'in nasıl hesaplandığına bağlı olarak, sonraki GUID'leri tahmin etmek mümkündür ve genellikle oldukça basittir (onları hesaplayan makineye ve saate bağlı olduklarından). "Olasılık değil", "çok küçük olasılıkla" demek istiyorsun, ama tamamen rastgele dizeler için bile "imkansız" diyemezsin. Regex'iniz sonsuz sayıda dizgiyle eşleşecek - bu soru hiçbir şeyle eşleşmeyen bir dizge arıyor. Hiç.
Ferdinand Beyer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.