Soru Bir kelime içermeyen bir satırı eşleştirmek için normal ifade?


Bir kelimeyi eşleştirmek ve diğer araçları kullanarak eşleşmeleri tersine çevirmek mümkün olduğunu biliyorum (ör. grep -v). Ancak, satırları eşleştirmek mümkün olup olmadığını bilmek istiyorum yapamaz Düzenli bir ifade kullanarak belirli bir kelimeyi (ör. hede) içerir.

Giriş:

hoho
hihi
haha
hede

Kod:

grep "<Regex for 'doesn't contain hede'>" input

Istenilen çıktı:

hoho
hihi
haha

3567


Menşei


Muhtemelen birkaç yıl geçti, ama neyin yanlış olduğunu: ([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*? Fikir basit. İstenmeyen dizenin başlangıcını görene kadar eşleşmeye devam edin, ardından yalnızca dizenin bitmemiş olduğu N-1 durumlarında (N dizenin uzunluğunda olduğu yerde) eşleşin. Bu N-1 vakaları “izleyenlerde e-olmayan”, “takip etmeyenler” ve “hed-e-olmayan” ile takip edilmektedir. Bu N-1 vakalarını geçmeyi başardıysanız, başarılı bir şekilde vermedi Aramaya başlayabilmeniz için istenmeyen dizeyle eşleştirin [^h]* tekrar - stevendesu
@stevendesu: bunu 'çok-çok-uzun-kelime' ya da daha iyi bir yarım cümle için deneyin. İyi eğlenceler. BTW, neredeyse okunamaz durumda. Performans etkisi hakkında bilmiyorum. - Peter Schuetze
@PeterSchuetze: Elbette çok uzun kelimeler için güzel değil, ama bu geçerli ve doğru bir çözümdür. Performansa ilişkin testler yapmadığım halde, bir h (veya kelimenin ilk cümlesi, vb.) Görülene kadar, ikinci kuralların çoğunun yok sayılmasından dolayı çok yavaş olduğunu hayal edemezdim. Yinelemeli birleştirme kullanarak uzun dizeler için düzenli ifade dizesini kolayca oluşturabilirsiniz. Çalışırsa ve hızlı bir şekilde üretilebilirse, okunabilirlik önemli midir? Yorumlar budur. - stevendesu
@stevendesu: Daha sonra bile, ama bu cevap neredeyse tamamen yanlıştır. bir şey için, konunun "belirli bir sözcüğü içermeyen [eşleşme çizgileri] eşleşmesi gereken" olması koşuluyla, nesnenin, olması gerekmemesi gereken "h" yi içermesi gerekir. İç grubun isteğe bağlı olmasını ve modelin sabitlendiğini varsayalım: ^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$  Bu, "hede" örneklerinin "het" gibi "hede" gibi kısmi örneklerinden önce gerçekleşmesi durumunda başarısız olur. - jaytea
Bu soruya eklendi. Yığın Taşması Düzenli İfade SSS"Gelişmiş Regex-Fu" altında. - aliteralmind


Cevaplar:


Regex'in ters eşleştirmeyi desteklemediği fikri tam olarak doğru değildir. Olumsuz bakışları kullanarak bu davranışı taklit edebilirsiniz:

^((?!hede).)*$

Yukarıdaki normal ifade, herhangi bir dizeyle veya satır sonu olmayan satırlarla eşleşecektir. değil (alt) 'hede' dizesini içerir. Bahsedildiği gibi, bu regex'in “iyi” olduğu bir şey değildir (ya da yapmalı), ama yine de, olduğu mümkün.

Ayrıca, satır sonu karakterlerini de eşleştirmeniz gerekirse, DOT-ALL değiştirici (takip s aşağıdaki desende):

/^((?!hede).)*$/s

veya satır içi kullanın:

/(?s)^((?!hede).)*$/

(nerede /.../ regex sınırlayıcılarıdır, yani, kalıbın bir parçası değildir)

DOT-ALL değiştiricisi mevcut değilse, aynı davranışı karakter sınıfıyla taklit edebilirsiniz. [\s\S]:

/^((?!hede)[\s\S])*$/

açıklama

Bir dize sadece bir listesi n karakter. Her karakterden önce ve sonra boş bir dize var. Bir liste n karakterler olacak n+1 boş dizeler. Dize düşünün "ABhedeCD":

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘

index    0      1      2      3      4      5      6      7

nerede eBoş dizeler. Regex (?!hede). hiçbir alt tabaka olup olmadığını görmek için ileriye bakar "hede" Görülecek ve eğer durum buysa (yani başka bir şey görülürse) . (nokta), satır sonu dışındaki herhangi bir karakterle eşleşir. Bakışlar da denir sıfır genişliği iddialar çünkü yapmıyorlar tüketmek herhangi bir karakter. Sadece bir şeyi doğrularlar / doğrularlar.

Yani, benim örneğimde, her boş dizenin, ilk önce, yok olup olmadığını görmek için doğrulanır. "hede" Bir karakter tarafından tüketilmeden önce . (nokta). Regex (?!hede). Bunu sadece bir kez yapar, bu yüzden bir grupta sarılır ve sıfır veya daha fazla kez tekrarlanır: ((?!hede).)*. Son olarak, girişin tamamının tüketildiğinden emin olmak için girişin başlangıcı ve sonu sabitlenir: ^((?!hede).)*$

Gördüğünüz gibi, giriş "ABhedeCD" çünkü başarısız olur e3, normal ifade (?!hede) başarısız olur olduğu  "hede" ileride!).


4859



Bu şeyin normal bir şekilde kötü bir şey olduğunu söyleyecek kadar ileri gitmezdim. Bu çözümün rahatlığı oldukça belirgindir ve programatik bir aramayla kıyaslandığında performans vuruşu çoğu zaman önemsiz olacaktır. - Archimaredes
Kesin bir şekilde negatif loook-ahead, düzenli ifadeyi düzenli yapmaz. - Peter K
@PeterK, elbette, ama bu SO, MathOverflow veya CS-Stackexchange değil. Burada bir soru sorduran insanlar genellikle pratik bir cevap arıyorlar. Çoğu kütüphane veya araç (gibi grepOP'in “regex-support” ile bahsettiği, hepsinin teorik anlamda düzenli olmayan mizaçları vardır. - Bart Kiers
@Bart Kiers, cevap vermene gerek yok, sadece bu terminoloji kötüye kullanımı beni biraz rahatsız ediyor. Buradaki gerçekten kafa karıştırıcı kısım, katı anlamda düzenli ifadelerin OP'nin istediği şeyi yapabilmesidir, ama bunları yazmanın ortak dili buna izin vermez, bu da görünüşe benzeyen (matematiksel olarak çirkin) geçici çözümlere yol açar. Bakınız bu cevap Aşağıda ve benim yorumum (teorik olarak hizalanmış) yapmak için uygun bir yol var. Söylemeye gerek yok, büyük girdilerde daha hızlı çalışır. - Peter K
Vim'de bunu nasıl yapacağınızı merak ettiyseniz: ^\(\(hede\)\@!.\)*$ - baldrs


Çözümüne dikkat edin değil ile başla “Hede”:

^(?!hede).*$

genellikle çözümden çok daha verimlidir değil içermek “Hede”:

^((?!hede).)*$

İlk, “hede” yi sadece her pozisyonda değil, giriş dizisinin ilk pozisyonunda kontrol eder.


606



Teşekkürler, string dos ^ ((?! \ D {5,}).) * Karakterlerini içermediğini doğrulamak için kullandım. - Samih A
^((?!hede).)*$ Veri kümesinden bir dize çıkarmak için jQuery DataTable eklentisini kullanarak çalıştım - Alex
Merhaba! Ben yapamam değil son "hede" ile regex. Yardım edebilir misin? - Aleks Ya
@AleksYa: sadece "içerir" sürümünü kullanın ve son dizeyi arama dizesine ekleyin: dizgeyi "hede" den "hede $" ye "eşleşmeyecek" olarak değiştirin - Nyerguds
@AleksYa: End değil sonu sürümü, negatif lookbehind kullanılarak yapılabilir: (.*)(?<!hede)$. @Nyerguds 'versiyonu da işe yarayacak, ancak yanıtın gösterdiği performans noktasını tamamen özlüyor. - thisismydesign


Eğer grep için kullanıyorsun, kullanabilirsin grep -v hede hede içermeyen tüm satırları almak.

ETA Ah, soruyu yeniden okurken, grep -v Muhtemelen "araçlar seçenekleri" ile kastettiğinizdir.


165



İpucu: ne istemediğinizi aşamalı olarak filtrelemek için: grep -v "hede" | grep -v "hihi" | ...vb. - Olivier Lalonde
Veya sadece bir işlem kullanarak grep -v -e hede -e hihi -e ... - Olaf Dietsche
Ya da sadece grep -v "hede\|hihi" :) - Putnik
Filtrelemek istediğiniz birçok deseniniz varsa, bunları bir dosyaya koyun ve kullanın grep -vf pattern_file file - codeforester
Ya da sadece egrep veya grep -Ev "hede|hihi|etc" garip kaçıştan kaçınmak için. - Amit Naidu


Cevap:

^((?!hede).)*$

Açıklama:

^dizenin başlangıcı ( grubu ve \ 1'e yakala (0 veya daha fazla kez (mümkün olan en fazla miktarla eşleşir)),
(?! olmadığını görmek için ileriye bak

hedesenin dizgin

) ileriye bakmanın sonu, . \ n dışında herhangi bir karakter
)* \ 1'in sonu (Not: Bu yakalamada bir niceleyici kullandığınız için, yalnızca yakalanan modelin en son tekrarı \ 1'de saklanır)
$ isteğe bağlı bir \ n'den önce ve dizenin sonu


122



çok sayıda kelime kullanarak yüce metin 2 benim için çalıştı harika^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$' - Damodar Bashyal
@DamodarBashyal Biliyorum, burada epey geç kaldım, ama orada ikinci terimi tamamen kaldırabilirdiniz ve aynı sonuçları elde edersiniz. - forresthopkinsa


Verilen cevaplar gayet iyi, sadece akademik bir nokta:

Teorik bilgisayar bilimleri anlamında düzenli ifadeler ABLE DEĞİLDİR Bunu böyle yap. Onlar için böyle bir şeye bakmak zorunda kaldılar:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

Bu sadece bir TAM eşleşme yapar. Alt eşlemeler için yapmak bile daha garip olurdu.


90



Dikkat edilmesi gereken önemli nokta, sadece temel POSIX.2 düzenli ifadeleri kullanmaktadır ve bu nedenle PCRE mevcut olmadığında daha fazla taşınabilirdir. - Steve-o
Katılıyorum. Çoğu düzenli ifadeler, normal olmayan diller değilse ve sınırlı bir otomata tarafından tanınamadıysa. - ThomasMcLeod
@ThomasMcLeod, Hades32: Söyleyebilecek herhangi bir normal dilin alemleri içinde mi?değil' ve 'veYanı sıra ‘veyaExpression gibi bir ifadenin(hede|Hihi)‘? (Bu CS için bir soru olabilir.) - James Haigh
@JohnAllen: BEN Mİ!!! … Aslında, gerçek ifadesi değil, aynı zamanda hesaplama karmaşıklığına da yakından benzeyen akademik referans; PCRE'ler temelde POSIX normal ifadeleriyle aynı verimliliği garanti edemez. - James Haigh
Üzgünüz-bu cevap sadece işe yaramaz, hhehe ile eşleşecek ve hatta kısmen (ikinci yarı) - Falco


Regex testini istiyorsanız bir tek eğer başarısız olursa tüm dize eşleşir, aşağıdakiler işe yarar:

^(?!hede$).*

Örneğin. - "foo" (yani "foofoo", "barfoo" ve "foobar" dışındaki tüm değerlere izin vermek istiyorsanız, ancak "foo" başarısız olur), şunu kullanın: ^(?!foo$).*

Tabi ki, eğer kontrol ediyorsanız kesin eşitlik, bu durumda daha iyi bir genel çözüm, dize eşitliğini kontrol etmektir, yani.

myStr !== 'foo'

Olumsuzluğu bile koyabilirsiniz dışında herhangi bir regex özelliğine ihtiyacınız varsa test (burada, büyük harf duyarsızlığı ve aralık eşleşmesi):

!/^[a-f]oo$/i.test(myStr)

Bununla birlikte, üstte regex çözümü yararlı olabilir, ancak pozitif bir regex testinin gerekli olduğu durumlarda (belki de bir API tarafından).


49



whitespaces hakkında ne dersiniz? Örneğin, testin string ile başarısız olmasını istiyorsam " hede "? - eagor
@eagor the \s yönerge tek bir beyaz karakterle eşleşir - Roy Tinker
teşekkürler, ancak bu işi yapmak için normal ifadeyi güncellemeyi başaramadım. - eagor
@eagor: ^(?!\s*hede\s*$).* - Roy Tinker


İşte iyi bir açıklama Bu nedenle keyfi bir normal ifadeyi iptal etmek kolay değildir. Ancak diğer cevaplarla aynı fikirdeyim: eğer bu bir varsayımsal sorudan başka bir şeyse, o zaman burada bir regex doğru seçim değildir.


48



Bazı araçlar ve özellikle de mysqldumpslow, verileri filtrelemek için bu yolu sunar, bu nedenle, böyle bir durumda, bunu yapmak için bir regex bulmak, aracı yeniden yazmanın dışında en iyi çözümdür (bunun için çeşitli yamalar MySQL AB / Sun'a dahil edilmemiştir). / Oracle. - FGM
Durumumu tam olarak anlatacağım. Hız şablonu motoru, ne zaman bir dönüşümü (html kaçış) uyguladığına karar vermek için düzenli ifadeler kullanır ve bir durumda HARİÇ bir şekilde çalışmasını isterim. - Henno Vermeulen
Hangi alternatif var? Normal ifadenin yanı sıra hassas bir dizge oluşturabilecek hiçbir şeyle karşılaşmadım. Eğer OP bir programlama dili kullanıyorsa, başka araçlar da mevcut olabilir, fakat eğer kod yazmıyorsa, muhtemelen başka bir seçenek yoktur. - kingfrito_5005
Regex'in mevcut en iyi seçim olduğu varsayımsal olmayan birçok senaryodan biri: Günlük çıktılarını gösteren bir IDE (Android Studio) içerisindeyim ve sağlanan tek filtreleme araçları şunlardır: düz dizeler ve normal ifadeler. Bunu düz dizelerle yapmaya çalışmak tam bir başarısızlık olurdu. - LarsH


FWIW, düzenli dillerin (akılcı dillerin) tamamlayıcı olarak kapatıldığından, başka bir ifadeyi reddeden düzenli bir ifadeyi (akılcı bir ifade) bulmak her zaman mümkündür. Ancak bunu pek çok araç uygulamıyor.

Vcsn bu operatörü destekler ( {c}, postfix).

Önce ifadelerinizin türünü tanımlayın: etiketler harftir (lal_char) almak için a için z örneğin (tamamlama ile çalışırken alfabenin tanımlanması elbette çok önemlidir) ve her kelime için hesaplanan "değer" sadece bir Boole'dur: true kelime kabul edilir false, reddedildi.

Python'da:

In [5]: import vcsn
        c = vcsn.context('lal_char(a-z), b')
        c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 𝔹

o zaman ifadeni girersin:

In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c

bu ifadeyi bir otomatikma dönüştürün:

In [7]: a = e.automaton(); a

The corresponding automaton

Son olarak, bu otomatik dönüşü basit bir ifadeye dönüştürün.

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

nerede + genellikle belirtilir |, \e boş kelimeyi belirtir, ve [^] genellikle yazılır . (herhangi bir karakter). Yani, biraz yeniden yazarak ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*.

Bu örneği görebilirsiniz İşteve Vcsn'yi çevrimiçi deneyin Orada.


44



Doğru, ama çirkin ve sadece küçük karakter kümeleri için yapılabilir. Unicode dizeleri :-) ile bunu yapmak istemiyorsunuz - reinierpost
Buna izin veren daha fazla araç var, en etkileyici olanlardan biri. Ragel. Orada hizalı bir eşleşme için (herhangi bir * - ('hehe' any *)) veya hizalı olmayanlar için (- herhangi bir * - ('hehe' any *)) olarak yazılır. - Peter K
@reinierpost: neden çirkin ve unicode ile ilgili problem nedir? İkisinde de aynı fikirdeyim. (Vcsn ile ilgili deneyimim yok, ancak DFA ile var). - Peter K
Regexp ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).* benim için çalışmadı egrep. Uyumlu hede. Ayrıca başlangıç ​​ve bitişe demirlemeyi denedim ve hala işe yaramadı. - Pedro Gimeno
@PedroGimeno Bağlandığınızda, bu regex'i önce parens'e koyduğunuzdan emin oldunuz? Aksi takdirde çapalar ve | güzel oynamaz. '^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'. - akim


Deneyler

Sunulan bazı Seçeneklerin değerlendirilmesi ve bazı yeni Özelliklerin kullanılmasının yanı sıra performanslarını karşılaştırmaya karar verdim. .NET Regex Engine'de Kıyaslama: http://regexhero.net/tester/

Karşılaştırma Metni:

İlk 7 satır eşleşmemelidir, çünkü aradıkları ifade içerdiklerinden, alt satırlar eşleşmelidir!

Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.

Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex  Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

Sonuçlar:

Sonuçlar, 3 çalışmanın ortancası olarak saniyede yineleme sayısıdır - Büyük Sayı = Daha İyi

01: ^((?!Regex Hero).)*$                    3.914   // Accepted Answer
02: ^(?:(?!Regex Hero).)*$                  5.034   // With Non-Capturing group
03: ^(?>[^R]+|R(?!egex Hero))*$             6.137   // Lookahead only on the right first letter
04: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$       7.371   // Logic Branch: Find Regex Hero? match nothing, else anything

P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT))  ?????   // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ?????   // Direct COMMIT & FAIL in Perl

.NET eylem fiillerini desteklemediğinden (* FAIL, vb.) P1 ve P2 çözümlerini test edemedim.

Özet:

Önerilen çözümlerin çoğunu test etmeye çalıştım, bazı kelimeler için bazı Optimizasyonlar mümkün. Örneğin, arama dizisinin ilk iki harfi aynı değilse, 03 yanıtı genişletilebilir. ^(?>[^R]+|R+(?!egex Hero))*$ küçük bir performans artışıyla sonuçlanır.

Ancak en okunabilir ve en yüksek performansa sahip en hızlı çözüm, koşullu bir ifade kullanılarak 05 olarak görünüyor. veya kantitatif niceleyiciyle. Perl çözümlerinin daha hızlı ve daha kolay okunabilmesi gerektiğini düşünüyorum.


39



Zaman geçirmelisin ^(?!.*hede) çok. /// Ayrıca, eşleşen dizge ve eşleşmeyen corpus için ifadeleri ayrı ayrı sıralamak daha iyidir çünkü genellikle çoğu satırın ya da satırların çoğunun yapmadığı bir durumdur. - ikegami