Kelime içermeyen bir satırla eşleşecek normal ifade


4293

Bir kelimeyi eşleştirmenin ve daha sonra diğer araçları (örn. grep -v) Kullanarak eşleşmeleri tersine çevirmenin mümkün olduğunu biliyorum . Ancak, belirli bir kelime içermeyen satırları, örneğin hedenormal bir ifade kullanarak eşleştirmek mümkün müdür ?

Giriş:

hoho
hihi
haha
hede

Kod:

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

Istenilen çıktı:

hoho
hihi
haha

84
Muhtemelen birkaç yıl geç, ama yanlış olan ne: ([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*? Fikir basit. İstenmeyen dizenin başlangıcını görene kadar eşleştirmeye devam edin, ardından yalnızca dizenin bitmemiş olduğu N-1 örneklerinde eşleşmeye devam edin (burada N dizenin uzunluğudur). Bu N-1 vakaları "h ardından e olmayan", "o d olmayan" ve "hed ardından e olmayan" şeklindedir. Bu N-1 vaka geçmek başardı, başarıyla vermedi Aradığınız başlayabilirsiniz böylece istenmeyen dizeyle eşleşen [^h]*tekrar
stevendesu

323
@stevendesu: bunu 'çok-çok-uzun-kelime' veya daha iyi bir yarım cümle için deneyin. İyi eğlenceler yazarak. BTW, neredeyse okunamıyor. Performans etkisi hakkında bilmiyorum.
Peter Schuetze

13
@PeterSchuetze: Elbette çok uzun kelimeler için hoş değil, ama geçerli ve doğru bir çözüm. Performans üzerinde test yapmama rağmen, h (veya kelimenin, cümlenin, vb. İlk harfini) görene kadar ikinci kuralların çoğu göz ardı edildiğinden, bunun çok yavaş olduğunu hayal etmem. Yinelemeli birleştirme kullanarak uzun dizeler için regex dizesini kolayca oluşturabilirsiniz. Çalışıyorsa ve hızlı bir şekilde üretilebiliyorsa, okunabilirlik önemli mi? Yorumlar bunun için.
stevendesu

57
@stevendesu: Ben daha sonrayım, ama bu cevap neredeyse tamamen yanlış. bir şey için, görevin "belirli bir kelime içermeyen [eş] içermeyen satırlar" olduğu göz önüne alındığında "h" içermesi gerekir. iç grubu isteğe bağlı kılmak istediğinizi varsayalım ve kalıbın sabitlendiğini varsayalım: ^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$ "hede" örneklerinden önce "hhede" gibi kısmi "hede" örnekleri geldiğinde bu başarısız olur.
jaytea

8
Bu soru, "Gelişmiş Regex-Fu" altında Yığın Taşması Düzenli İfade SSS'ye eklenmiştir .
aliteralmind

Yanıtlar:


5892

Normal ifadenin ters eşleşmeyi desteklemediği düşüncesi tam olarak doğru değildir. Olumsuz bakışları kullanarak bu davranışı taklit edebilirsiniz:

^((?!hede).)*$

Regex yukarıda, bir çizgi ara vermeden herhangi bir dize veya satırla aynı olacak değil (alt) dize 'hede' içeren. Belirtildiği gibi, bu normal ifadede "iyi" bir şey değildir (veya yapmalıdır), ancak yine de mümkündür.

Ayrıca, satır sonu karakterlerini de eşleştirmeniz gerekiyorsa, DOT-ALL değiştiricisini kullanın ( saşağıdaki desende sondaki nokta):

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

veya satır içi kullanın:

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

( /.../normal ifade sınırlayıcıları nerede , yani desenin bir parçası değil)

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

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

açıklama

Dize yalnızca nkarakterlerin listesidir . Her karakterden önce ve sonra boş bir dize var. Yani nkarakter listesinin n+1boş dizeleri olacaktır . Dizeyi 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

burada eboş dizelerdir. Normal ifade, (?!hede).görünecek alt dize olup olmadığını görmek için ileriye bakar "hede"ve durum buysa (başka bir şey görülür), .(nokta) satır sonu dışındaki herhangi bir karakterle eşleşir. Etrafa, sıfır genişlik iddiası da denir, çünkü karakter tüketmezler . Sadece bir şeyi iddia ediyor / onaylıyorlar.

Yani, örneğimde, her boş dize, "hede"bir karakter .(nokta) tarafından tüketilmeden önce, önünüzde yok olup olmadığını görmek için onaylanır . Regex (?!hede).sıfır veya daha fazla kez bir grup sarılmış ve tekrarlanır, böylece yalnızca bir kez yapacağız: ((?!hede).)*. Son olarak, tüm girişin tüketildiğinden emin olmak için giriş başlangıcı ve giriş sonu sabitlenir:^((?!hede).)*$

Gördüğünüz gibi, giriş "ABhedeCD"nedeniyle başarısız olur e3regex, (?!hede)başarısız (orada olduğunu "hede" İlerideki!).


26
Ben bu regex kötü bir şey olduğunu söylemek kadar ileri gitmek değildir. Bu çözümün rahatlığı oldukça açıktır ve programlı bir aramaya kıyasla performans artışı genellikle önemsiz olacaktır.
Archimaredes

29
Açıkça söylemek gerekirse, olumsuz görüş sizi düzenli ifade eder.
Peter K

55
@PeterK, tabii, ama bu SO, MathOverflow veya CS-Stackexchange değil. Burada bir soru soran insanlar genellikle pratik bir cevap arıyorlar. grepRegex-destekli çoğu kütüphane veya araç ( OP'nin bahsettiği gibi), hepsi teorik anlamda onları normal olmayan mke özelliklerine sahiptir.
Bart Kiers

19
@Bart Kiers, cevap verdiğiniz bir suç yok, sadece bu terminolojinin kötüye kullanılması beni biraz rahatsız ediyor. Buradaki gerçekten kafa karıştırıcı kısım, katı anlamda düzenli ifadelerin OP'nin istediklerini çok fazla yapabileceğidir, ancak bunları yazmak için ortak dil buna izin vermez, bu da görünüm öncesi gibi (matematiksel olarak çirkin) geçici çözümlere yol açar. Lütfen aşağıdaki bu cevaba ve doğru şekilde yapmanın (teorik olarak hizalanmış) yorumuna bakın. Büyük girdilerde daha hızlı çalıştığını söylemeye gerek yok.
Peter K

17
Hiç vim bunu nasıl merak ^\(\(hede\)\@!.\)*$
ettiyseniz

738

Solüsyon o Not gelmez ile başlar “Hede” :

^(?!hede).*$

genellikle çok daha verimli çözümüne kıyasla vermez içeriyor “hede” :

^((?!hede).)*$

Birincisi “hede” yi, her pozisyonda değil, sadece giriş dizgisinin ilk pozisyonunda kontrol eder.


5
Teşekkürler, dize dos basamakları (^? (?! \ D {5,}). Basamak) içermediğini doğrulamak için kullandım.
Samih

2
Merhaba! Ben oluşturma olamaz gelmez sona "hede" ile regex. Bununla yardım edebilir misin?
Aleks Ya

1
@AleksYa: sadece "içerir" sürümünü kullanın ve son tutturucuyu arama dizesine ekleyin: dizeyi "
hedeften

2
@AleksYa: bitmez versiyonu olarak Negatif Geriye İlerleme kullanılarak yapılabilir: (.*)(?<!hede)$. @Nyerguds'ın sürümü de işe yarayacaktı, ancak yanıtın bahsettiği performans konusundaki noktayı tamamen kaçırdı.
thisismydesign

5
Neden bu kadar çok cevap söylüyor ^((?!hede).)*$? Kullanımı daha verimli değil ^(?!.*hede).*$mi? Aynı şeyi yapar ama daha az adımda
JackPRead

208

Eğer sadece grep için kullanıyorsun, sen kullanabilirsiniz grep -v hedehede içermeyen tüm satırları alır.

ETA Oh, soruyu yeniden okumak grep -vmuhtemelen "araç seçenekleri" ile kastettiğin şeydir.


22
İpucu: istemediğinizi aşamalı olarak filtrelemek için: grep -v "hede" | grep -v "hihi" | ...vb.
Olivier Lalonde

51
Veya sadece bir işlem kullanarakgrep -v -e hede -e hihi -e ...
Olaf Dietsche

15
Ya da sadece grep -v "hede\|hihi":)
Putnik

2
Filtrelemek istediğiniz birçok deseniniz varsa, bunları bir dosyaya koyun ve kullanıngrep -vf pattern_file file
codeforester

4
Ya da basitçe egrepya grep -Ev "hede|hihi|etc"da garip kaçmayı önlemek için.
Amit Naidu

160

Cevap:

^((?!hede).)*$

Açıklama:

^dizenin başlangıcı, (gruplandırılması ve yakalanması \ 1 (0 veya daha fazla kez (mümkün olan en fazla tutarla eşleşir)),
(?!yoksa,

hede dizeniz,

)ileriye bakmanın sonu, .\ n,
)*\ 1 dışında herhangi bir karakter (Not: bu yakalamada bir nicelik belirteci kullandığınız için, yakalanan desenin yalnızca LAST tekrarı \ 1'de depolanır)
$isteğe bağlı \ n, ve dizenin sonu


14
birden fazla kelime kullanarak yüce metin 2 benim için çalıştı harika ' ^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$'
Damodar Bashyal

3
@DamodarBashyal Burada oldukça geç kaldığımı biliyorum, ama orada ikinci terimi tamamen kaldırabilirsiniz ve aynı sonuçları elde edersiniz
forresthopkinsa

99

Verilen cevaplar gayet iyi, sadece akademik bir nokta:

Teorik bilgisayar bilimleri anlamında Düzenli İfadeler BU YAPILAMAZ . Onlar için böyle bir şeye benzemek zorundaydı:

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

Bu sadece TAM eşleşir. Alt maçlar için bunu yapmak daha da garip olurdu.


1
Bunun yalnızca temel POSIX.2 normal ifadelerini kullandığını ve dolayısıyla PCRE'nin kullanılamadığı zaman daha taşınabilir olduğunu belirtmek önemlidir.
Steve-o

5
Katılıyorum. Çoğu düzenli ifade olmasa da çoğu normal dil değildir ve sınırlı bir otomata tarafından tanınamaz.
ThomasMcLeod

@ThomasMcLeod, Hades32: ' değil ' ve ' ve ' yanı sıra ' ' gibi bir ifadenin ' veya ' diyebilmesi olası herhangi bir normal dilin alemlerinde (hede|Hihi)mi? (Bu belki CS için bir soru.)
James Haigh

7
@JohnAllen: ME !!! … Aslında, normal ifade değil, aynı zamanda hesaplama karmaşıklığı ile de yakından ilgili olan akademik referans; PCRE'ler temel olarak POSIX düzenli ifadeleriyle aynı verimliliği garanti edemez.
James Haigh

4
Üzgünüz -bu cevap işe yaramaz, hhehe ile eşleşir ve hatta kısmen (ikinci yarı) eşleşir
Falco

60

Normal ifade testinin yalnızca tüm dize eşleşmesi durumunda başarısız olmasını istiyorsanız , aşağıdakiler çalışır:

^(?!hede$).*

örn. - "foo" (örn. "foofoo", "barfoo" ve "foobar" hariç tüm değerlere izin vermek istiyorsanız ancak "foo" başarısız olur), şunu kullanın: ^(?!foo$).*

Tabii ki, tam eşitliği kontrol ediyorsanız , bu durumda daha iyi bir genel çözüm dize eşitliğini kontrol etmektir, yani

myStr !== 'foo'

Herhangi bir normal ifade özelliğine (burada, büyük / küçük harf duyarsızlığı ve aralık eşleşmesi) ihtiyacınız varsa , negatifliği testin dışına bile çıkarabilirsiniz :

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

Bununla birlikte, bu cevabın üst kısmındaki regex çözümü, pozitif bir regex testinin gerekli olduğu durumlarda (belki de bir API tarafından) yardımcı olabilir.


izleyen boşluklar ne olacak? Örneğin, eğer testin dizeyle başarısız olmasını istiyorsam " hede "?
eagor

@eagor \syönergesi tek bir boşluk karakteriyle eşleşiyor
Roy Tinker

teşekkürler, ancak bu işi yapmak için normal ifadeyi güncellemeyi başaramadım.
eagor

2
@eagor:^(?!\s*hede\s*$).*
Roy Tinker

52

FWIW, normal diller (rasyonel diller olarak da bilinir) tamamlama altında kapalı olduğundan, başka bir ifadeyi reddeden düzenli bir ifade (rasyonel ifade olarak da bilinir) bulmak her zaman mümkündür. Ancak bunu pek çok araç uygulamıyor.

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

İlk olarak ifadelerinizin türünü tanımlarsınız: etiketler, örneğin lal_charseçim ayapmak ziçin harf ( ) şeklindedir (tamamlama ile çalışırken alfabeyi tanımlamak elbette çok önemlidir) ve her kelime için hesaplanan "değer" sadece bir Boole'dir : truekelime kabul edilir false, reddedilir.

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}  𝔹

sonra ifadenizi girersiniz:

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

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

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

Karşılık gelen otomat

son olarak, bu otomatiği tekrar 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[^]))))[^]*

burada +genellikle belirtilir |, \eboş sözcüğü belirtir ve [^]genellikle yazılır .(herhangi bir karakter). Yani, biraz yeniden yazmayla ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*.

Bu örnek görebilirsiniz burada ve çevrimiçi Vcsn deneyin orada .


6
Doğru, ama çirkin ve sadece küçük karakter kümeleri için yapılabilir. Bunu Unicode dizeleriyle yapmak istemezsiniz :-)
reinierpost

Buna izin veren daha fazla araç var, en etkileyici olanlardan biri Ragel . Burada başlangıç ​​hizalamalı maç için (herhangi bir * - ('hehe' herhangi bir *)) veya hizalanmamış için (herhangi bir * - ('hehe' herhangi bir *)) olarak yazılacaktır.
Peter K

1
@reinierpost: neden çirkin ve unicode ile ilgili sorun nedir? İkisine de katlanamıyorum. (Vcsn ile hiçbir deneyimim yok, ama DFA ile var).
Peter K

3
@PedroGimeno Demir attığınızda, bu normal ifadeyi önce ebeveynlere koyduğunuzdan emin misiniz? Aksi takdirde çapalar arasındaki öncelikler ve |güzel oynamaz. '^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'.
akim

1
Bu yöntemin OP'nin istediği 'hede' sözcüğünü içermeyen satırlardan ziyade 'hede' kelimesi olmayan satırları eşleştirmek için olduğunu belirtmek gerekir . İkincisi için cevabımı görün.
Pedro Gimeno

51

İşte rasgele bir regex'i neden reddetmenin kolay olmadığına dair iyi bir açıklama . Yine de diğer cevaplara katılmalıyım: eğer bu varsayımsal bir sorudan başka bir şeyse, o zaman bir normal ifade burada doğru seçim değildir.


10
Bazı araçlar ve özellikle mysqldumpslow, yalnızca verileri filtrelemek için bu yolu sunar, bu nedenle böyle bir durumda, bunu yapmak için bir regex bulmak, aracı yeniden yazmak dışında en iyi çözümdür (bunun için çeşitli yamalar MySQL AB / Sun tarafından dahil edilmemiştir. / Oracle.
FGM

1
Durumuma tam olarak benziyor. Hız şablonu motoru ne zaman bir dönüşüm (kaçış html) uygulanacağına karar vermek için düzenli ifadeler kullanır ve ben her zaman bir durumda EXCEPT çalışmak istiyorum.
Henno Vermeulen

1
Ne alternatifi var? Ive regex yanı sıra kesin dize eşleme yapabileceği bir şey hiç karşılaşmadım. OP bir programlama dili kullanıyorsa, başka araçlar da olabilir, ancak kod yazmamakta ise, muhtemelen başka bir seçenek yoktur.
kingfrito_5005

2
Normal ifadenin en iyi seçenek olduğu varsayımsal olmayan birçok senaryodan biri: Günlük çıktısını gösteren bir IDE'de (Android Studio) ve sağlanan tek filtreleme araçları şunlardır: düz dizeler ve normal ifade. Bunu düz dizelerle yapmaya çalışmak tamamen başarısız olur.
LarsH

48

Negatif ileriye dönük olarak, düzenli ifade belirli bir desen içermeyen bir şeyle eşleşebilir. Bu, Bart Kiers tarafından cevaplanır ve açıklanır. Harika bir açıklama!

Ancak, Bart Kiers'ın cevabıyla, ileriye dönük kısım, herhangi bir tek karakterle eşleşirken 1 ila 4 karakter ileride test edecek. Bundan kaçınabiliriz ve ileriye doğru parçanın tüm metni kontrol etmesine izin verelim, 'hede' olmadığından emin olun ve sonra normal kısım (. *) Tüm metni bir kerede yiyebilir.

Geliştirilmiş normal ifade:

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

Negatif ileri okuma kısmındaki (*?) Tembel nicelik belirleyicinin isteğe bağlı olduğunu unutmayın, verilerinize bağlı olarak bunun yerine (*) açgözlü nicelik belirteci kullanabilirsiniz: 'hede' varsa ve metnin başlangıç ​​yarısında tembel nicelik belirleyici daha hızlı ol; aksi takdirde, açgözlü nicelik daha hızlı olur. Ancak 'hede' mevcut değilse, her ikisi de eşit yavaş olacaktır.

İşte demo kodu .

Lookahead hakkında daha fazla bilgi için lütfen şu makaleye göz atın : Lookahead ve Lookbehind'e hakim olma .

Ayrıca, karmaşık düzenli ifadeler oluşturmaya yardımcı olan bir JavaScript Düzenli İfade Oluşturucu olan RegexGen.js'ye de göz atın . RegexGen.js ile normal ifadeyi daha okunabilir bir şekilde oluşturabilirsiniz:

var _ = regexGen;

var regex = _(
    _.startOfLine(),             
    _.anything().notContains(       // match anything that not contains:
        _.anything().lazy(), 'hede' //   zero or more chars that followed by 'hede',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);

3
böylece verilen dizenin ^(?!.*(str1|str2)).*$
str1

1
Evet veya ^(?!.*?(?:str1|str2)).*$verilerinize bağlı olarak tembel nicelik belirteci kullanabilirsiniz: ?:Yakalamamız gerekmediğinden beri eklendi .
amobiz

Bu, 10xms'lik bir faktörün açık ara en iyi yanıtıdır. Jsfiddle kodunuzu ve sonuçlarınızı yanıta eklediyseniz insanlar bunu fark edebilir. Tembel versiyonun neden yokken açgözlü versiyondan daha hızlı olduğunu merak ediyorum. Aynı süreyi almamalılar mı?
user5389726598465

Evet, her ikisi de metnin tamamını test ettikleri için aynı süreyi alıyorlar.
amobiz

41

Deneyler

Sunulan Seçeneklerin bazılarını değerlendirmeye ve performanslarını karşılaştırmaya ve bazı yeni Özellikler kullanmaya karar verdim. .NET Regex Engine'de karşılaştırma: http://regexhero.net/tester/

Karşılaştırma Metni:

Aranan İfadeyi içerdikleri için ilk 7 satır eşleşmemeli, alt 7 satır 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ışma medyanı olarak saniyedeki yinelemelerdir - Daha 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 Fiilleri desteklemediğinden (* FAIL, vb.) P1 ve P2 çözümlerini test edemedim.

Özet:

En çok önerilen çözümleri test etmeye çalıştım, bazı kelimeler için bazı Optimizasyonlar mümkün. Örneğin, arama dizesinin ilk iki harfi Aynı değilse, cevap 03 ^(?>[^R]+|R+(?!egex Hero))*$küçük bir performans kazancı sağlayacak şekilde genişletilebilir .

Ancak, genel olarak en okunabilir ve performans açısından en hızlı çözüm, koşullu bir ifade kullanarak 05 veya uygun nicelik belirteciyle 04 gibi görünüyor. Bence Perl çözümleri daha hızlı ve daha kolay okunabilir olmalı.


5
Sen de zamanlamalısın ^(?!.*hede). /// Ayrıca, eşleşen satır ve eşleşen olmayan küme için ifadeleri ayrı ayrı sıralamak daha iyidir çünkü çoğu satır eşleşmesinin veya satırın çoğunun yapmadığı bir durumdur.
ikegami

32

Regex değil, ama ben gürültü ile ortadan kaldırmak için boru ile seri greps kullanmak mantıklı ve yararlı buldum.

Örneğin. tüm yorumları içermeyen bir apache yapılandırma dosyasında arama yapın

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

ve

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

Seri grep'in mantığı (yorum değil) ve (dir ile eşleşir)


2
Sanırım regex versiyonunu istiyorgrep -v
Angel.King.47

9
Bu tehlikeli. Ayrıca benzeri çizgiler özlüyorgood_stuff #comment_stuff
Xavi Montero

29

bununla, her pozisyonda bir ileriye bakmaktan kaçınmanız gerekir:

/^(?:[^h]+|h++(?!ede))*+$/

(.net için) eşdeğeri:

^(?>(?:[^h]+|h+(?!ede))*)$

Eski cevap:

/^(?>[^h]+|h+(?!ede))*$/

7
İyi bir nokta; Daha önce hiç kimse bu yaklaşımdan bahsetmediğine şaşırdım. Bununla birlikte, söz konusu normal ifade eşleşmeyen metne uygulandığında yıkıcı geri izlemeye eğilimlidir . İşte nasıl yapacağım:/^[^h]*(?:h+(?!ede)[^h]*)*$/
Alan Moore

... ya da tüm nicelik belirteçleri sahiplenebilirsiniz. ;)
Alan Moore

@Alan Moore - Ben de şaşırdım. Yorumunuzu (ve yığındaki en iyi normal ifadeyi) burada, ancak aynı modeli aşağıdaki bir cevapta yayınladıktan sonra gördüm.
ridgerunner

@ridgerunner, en iyi tho olmak zorunda değil. En iyi yanıtın daha iyi performans gösterdiği ölçütler gördüm. (Bu konuda şaşırdım.)
Qtax

23

Yukarıda bahsedilen (?:(?!hede).)*harika çünkü demirlenebilir.

^(?:(?!hede).)*$               # A line without hede

foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

Ancak bu durumda aşağıdakiler yeterli olacaktır:

^(?!.*hede)                    # A line without hede

Bu basitleştirme, "AND" cümleleri eklenmeye hazır:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same

20

İşte böyle yapardım:

^[^h]*(h(?!ede)[^h]*)*$

Diğer cevaplardan daha doğru ve daha verimli. Friedl'in "loop un-the-loop" verimlilik tekniğini uygular ve daha az geri takip gerektirir.


17

Negatif karakter sınıfına benzer bir kelimeyi reddetmek için bir karakteri eşleştirmek istiyorsanız:

Örneğin, bir dize:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

Kullanmayın:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

kullanın:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

Uyarı "(?!bbb)."ne ileriye dönük ne de ileriye dönüktür, örneğin akıntılıdır, örneğin:

"(?=abc)abcde", "(?!abc)abcde"

3
Perl regexp'lerinde "akım" yoktur. Bu gerçekten olumsuz bir ileri (önek (?!). Pozitif ileriye dönük öneki (?=, karşılık gelen geriye dönük ön ekleri sırasıyla (?<!ve (?<=olacaktır. Bir ileriye doğru, sonraki karakterleri (dolayısıyla “önde”) tüketmeden okumanız anlamına gelir. Yeniden inceleme, daha önce tüketilmiş olan karakterleri kontrol ettiğiniz anlamına gelir.
Didier L

14

Benim düşünceme göre, üst cevabın daha okunabilir bir varyantı:

^(?!.*hede)

Temel olarak, "satırın başında ve sadece 'hede' yoksa maç" - böylece gereksinim neredeyse doğrudan normal ifade çevrildi.

Tabii ki, birden fazla arıza gereksiniminiz olabilir:

^(?!.*(hede|hodo|hada))

Ayrıntılar: ^ bağlantısı, normal ifade motorunun dizedeki her konumda eşleşmeyi yeniden denememesini sağlar;

Baştaki ^ çapa, satırın başlangıcını temsil eder. Grep aracı, her satırı birer birer eşleştirir, çok satırlı bir dizeyle çalıştığınız bağlamlarda "m" bayrağını kullanabilirsiniz:

/^(?!.*hede)/m # JavaScript syntax

veya

(?m)^(?!.*hede) # Inline flag

Çoklu olumsuzlama ile mükemmel örnek.
Peter Parada

Üst yanıttan bir fark, bunun hiçbir şeyle eşleşmemesi ve "hede" olmadan tüm çizgiyle eşleşmesidir
Z. Khullah

13

OP Tag, Regex'in içinde kullanılacağı içeriği (programlama dili, editör, araç) belirtmek için belirtmedi veya yazdı.

Benim için bazen bunu kullanarak bir dosyayı düzenlerken yapmam gerekir Textpad.

Textpad bazı Regex'i destekler, ancak ileri veya geri bakışı desteklemez, bu nedenle birkaç adım alır.

Dize İÇERMEZ tüm satırları korumak için arıyorum hede, ben böyle yapmak istiyorum:

1. Herhangi bir metni içeren her satırın başına benzersiz bir "Etiket" eklemek için tüm dosyayı arayın / değiştirin.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Dizeyi içeren tüm satırları silin hede(yedek dize boştur):

    Search string:<@#-unique-#@>.*hede.*\n  
    Replace string:<nothing>  
    Replace-all  

3. Bu noktada, kalan tüm satırlar dizeyi İÇERMEZhede . Benzersiz "Etiket" i tüm satırlardan kaldırın (yedek dize boştur):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

Artık orijinal metni, dizeyi içeren tüm satırlar hedekaldırılmış olarak aldınız .


Ben sadece bir şey Dize İÇERMEZ satırlara başka bir şey arıyorsanız hede, ben böyle yapmak istiyorum:

1. Herhangi bir metni içeren her satırın başına benzersiz bir "Etiket" eklemek için tüm dosyayı arayın / değiştirin.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Dizeyi içeren tüm satırlar hedeiçin benzersiz "Etiket" i kaldırın:

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3. Bu noktada, benzersiz "Etiket" ile başlayan tüm satırlar , dizeyi İÇERMEZhede . Şimdi Başka Bir Şeyimi sadece bu çizgilere yapabilirim.

4. Ben bittiğinde, tüm satırlardan benzersiz "Tag" kaldırmak (yedek dize boş):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

12

Sorulan soruya başka hiç kimse doğrudan cevap vermediğinden, ben yapacağım.

Cevap POSIX ile grepbu talebi tam anlamıyla karşılamak imkansızdır:

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

Bunun nedeni, POSIX'in grepyalnızca bu görevi yerine getirecek kadar güçlü olmayan Temel Düzenli İfadeler ile çalışması gerektiğidir (alternatif ve parantez eksikliği nedeniyle normal dilleri ayrıştıramazlar).

Ancak, GNU grepbuna izin veren uzantıları uygular. Özellikle, \|GNU'nun BRE'leri uygulamasında alternatif operatör ve \(ve \)parantezler. Normal ifade motorunuz alternatifi, negatif parantez ifadelerini, parantezleri ve Kleene yıldızını destekliyorsa ve dizenin başına ve sonuna demirleyebiliyorsa, bu yaklaşım için ihtiyacınız olan tek şey budur. Bununla birlikte, negatif setlerin [^ ... ]bunlara ek olarak çok uygun olduğuna dikkat edin , çünkü aksi takdirde, bunları (a|b|c| ... )sette olmayan, son derece sıkıcı ve aşırı uzun olan her karakteri listeleyen formun bir ifadesiyle değiştirmeniz gerekir, tüm karakter kümesi Unicode'dur.

GNU ile grepcevap şöyle olacaktır:

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

( Grail ve elle yapılan bazı diğer optimizasyonlarla birlikte bulunur ).

Ayrıca uygular bir aracı kullanabilirsiniz Normal İfadeleri Extended gibi egrepters eğik kurtulmak için,:

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

İşte sınamak için bir komut dosyası ( testinput.txtgeçerli dizinde bir dosya oluşturduğunu unutmayın ):

#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$"

# First four lines as in OP's testcase.
cat > testinput.txt <<EOF
hoho
hihi
haha
hede

h
he
ah
head
ahead
ahed
aheda
ahede
hhede
hehede
hedhede
hehehehehehedehehe
hedecidedthat
EOF
diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

Sistemimde:

Files /dev/fd/63 and /dev/fd/62 are identical

beklenildiği gibi.

Detaylarla ilgilenenler için kullanılan teknik, kelimeyle eşleşen normal ifadeyi sonlu bir otomasyona dönüştürmek, daha sonra her kabul durumunu kabul etmeme ve tersine çevirerek otomatı ters çevirmek ve daha sonra elde edilen FA'yı geri dönüştürmektir. düzenli bir ifade.

Son olarak, herkesin de belirttiği gibi, normal ifade motorunuz negatif ileriye bakmayı destekliyorsa, bu işi çok basitleştirir. Örneğin, GNU grep ile:

grep -P '^((?!hede).)*$' input

Güncelleme: Geçenlerde Kendall Hopkins'in Grail'e benzer bir işlev sağlayan PHP'de yazılmış mükemmel FormalTheory kütüphanesini buldum . Bunu ve kendim tarafından yazılmış bir sadeleştiriciyi kullanarak, bir giriş ifadesi (yalnızca şu anda alfasayısal ve boşluk karakterleri destekleniyor) verilen negatif düzenli ifadelerin çevrimiçi oluşturucusunu yazabildim: http://www.formauri.es/personal/ pgimeno / misc / olmayan maç-regex /

İçin hedeo çıkarır:

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

bu yukarıdakine eşdeğerdir.


11

Ruby-2.4.1'in piyasaya sürülmesinden bu yana, Ruby'nin Normal İfadelerinde yeni Abonelik Operatörünü kullanabiliriz

resmi doktordan

(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.

Böylece, sizin durumunuzda ^(?~hede)$iş sizin için yapar

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]

9

PCRE fiili aracılığıyla (*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

Bu, tam dizeyi içeren hedeve kalan tüm satırlarla eşleşen satırı tamamen atlar .

DEMO

Parçaların yürütülmesi:

Yukarıdaki regex'i iki kısma ayırarak ele alalım.

  1. Sembolden önceki bölüm |. Parça eşleştirilmemelidir .

    ^hede$(*SKIP)(*F)
  2. Sembolden sonraki bölüm |. Parça eşleştirilmelidir .

    ^.*$

BÖLÜM 1

Regex motoru ilk bölümden itibaren çalışmaya başlayacaktır.

^hede$(*SKIP)(*F)

Açıklama:

  • ^ Başlangıçta olduğumuzu iddia ediyor.
  • hede Dizeyle eşleşir hede
  • $ Satır sonunda olduğumuzu ileri sürüyor.

Böylece dizeyi içeren satır hedeeşleşir. Regex motoru şu gördükten sonra (*SKIP)(*F)( : Not Sen yazabilirsiniz (*F)olarak(*FAIL) fiil, bu atlar) ve eşleme başarısız olun. |değişiklik veya mantıksal VEYA operatörü olarak adlandırılan PCRE fiilinin yanında eklenen ve tüm sınırlarla eşleşen tüm satırlar, satır dışındaki tüm satırlardaki her bir karakter arasında tam bir dize içerir hede. Demoya buradan bakın . Yani, kalan dizeden karakterleri eşleştirmeye çalışır. Şimdi ikinci kısımdaki normal ifade uygulanacak.

BÖLÜM 2

^.*$

Açıklama:

  • ^ Başlangıçta olduğumuzu iddia ediyor. yani, satır dışındaki tüm satır başlangıçlarıyla eşleşir hede. Demoya buradan bakın .
  • .*Çok .Satır modunda, satırsonu veya satır başı karakterleri dışında herhangi bir karakterle eşleşir. Ve *önceki karakteri sıfır veya daha fazla kez tekrar ederdi. Yani .*tüm çizgiyle eşleşecekti. Demoya buradan bakın .

    Hey neden. + Yerine * eklediniz?

    Çünkü .*boş bir satırla eşleşir, ancak boş bir satırla .+eşleşmez. hedeGirişteki boş satırlar da olabilir, ancak tüm satırları eşleştirmek istiyoruz . yani .*yerine kullanmalısınız .+. .+önceki karakteri bir veya daha fazla kez tekrarlar. Bkz . Burada.* boş bir satırla eşleşir .

  • $ Burada hat çapasının sonu gerekli değildir.


7

İlk eşleşmeyi yapmak için kodunuzdaki iki normal ifade için daha sürdürülebilir olabilir ve eğer eşleşirse, örneğin engellemek istediğiniz aykırı durumları kontrol etmek için ikinci normal ^.*(hede).*ifadeyi çalıştırıp kodunuzda uygun mantığa sahip olabilirsiniz.

Tamam, bu gerçekten yayınlanan yayınlanan soruya bir cevap değildir ve aynı zamanda tek bir regex biraz daha fazla işleme kullanabilirsiniz itiraf ediyorum. Ancak, buraya gelen bir durum için hızlı bir acil durum düzeltmesi arayan geliştiriciler için, bu çözüm göz ardı edilmemelidir.


5

TXR Dil regex yadsımasını destekler.

$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)'  Input

Daha karmaşık bir örnek: alt dize aile başlayan ve biten zancak alt dizeyi içermeyen tüm satırlarla eşleşir hede:

$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az         <- echoed
az
abcz       <- echoed
abcz
abhederz   <- not echoed; contains hede
ahedez     <- not echoed; contains hede
ace        <- not echoed; does not end in z
ahedz      <- echoed
ahedz

Regex olumsuzlaması kendi başına özellikle yararlı değildir, ancak kavşağa sahip olduğunuzda, her şey ilginçleşir, çünkü tam bir boolean set işlemi setiniz vardır: "bununla eşleşen seti, bununla eşleşen şeyler hariç" ifade edebilirsiniz.


Elastik arama Lucene tabanlı normal ifade için de çözüm olduğunu unutmayın.
Wiktor Stribiżew

5

Başka bir seçenek, olumlu bir ileriye bakmak ve hehegiriş satırında herhangi bir yer olup olmadığını kontrol etmektir, o zaman buna benzer bir ifade ile bunu reddederiz:

^(?!(?=.*\bhede\b)).*$

kelime sınırları ile.


İfade regex101.com'un sağ üst panelinde açıklanır , eğer keşfetmek / basitleştirmek / değiştirmek isterseniz ve bu bağlantıda , isterseniz bazı örnek girişlerle nasıl eşleşeceğini izleyebilirsiniz.


RegEx Devresi

jex.im düzenli ifadeleri görselleştirir:

resim açıklamasını buraya girin


4

Aşağıdaki işlev, istediğiniz çıktıyı almanıza yardımcı olacaktır

<?PHP
      function removePrepositions($text){

            $propositions=array('/\bfor\b/i','/\bthe\b/i'); 

            if( count($propositions) > 0 ) {
                foreach($propositions as $exceptionPhrase) {
                    $text = preg_replace($exceptionPhrase, '', trim($text));

                }
            $retval = trim($text);

            }
        return $retval;
    }


?>

2

^ ((?! hede).) * $ zarif bir çözümdür, ancak karakterleri tükettiği için onu diğer kriterlerle birleştiremezsiniz. Örneğin, "hede" nin olup olmadığını ve "haha" nın varlığını kontrol etmek istediğinizi varsayalım. Bu çözüm, karakterleri tüketmeyeceği için işe yarar:

^ (?!. \ bhede \ b) (? =. \ bhaha \ b)


1

PCRE'nin geri izleme kontrol fiillerini kelime içermeyen bir satırla eşleştirmek için nasıl kullanılır

Daha önce kullanılmadığını gördüğüm bir yöntem:

/.*hede(*COMMIT)^|/

Nasıl çalışır

İlk olarak, hattın herhangi bir yerinde "hede" bulmaya çalışır. Başarılı olursa, bu noktada, (*COMMIT)motora sadece bir arıza durumunda geri izlemeyi değil, aynı zamanda bu durumda başka bir eşleştirme girişiminde bulunmamasını söyler. Ardından, muhtemelen eşleşemeyen bir şeyi eşleştirmeye çalışırız (bu durumda ^).

Bir satır "hede" içermiyorsa, ikinci alternatif olan boş bir alt desen, konu dizesiyle başarıyla eşleşir.

Bu yöntem, negatif bir ileriye bakmaktan daha etkili değildir, ancak birisinin şık bulması ve diğer, daha ilginç uygulamalar için bir kullanım bulması durumunda bunu buraya atacağımı düşündüm.


0

Daha basit bir çözüm değil operatör kullanmaktır !

Sizin eğer deyim karşılamaları gerektiğini ve "Kapsam dışı" eşleşmiyor "içerir".

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

RegEx tasarımcılarının operatörlerin kullanılmamasını beklediğine inanıyorum.


0

Do bir hat (aynı tüm hatları karşı) segmentlerini maç yapabiliyor bir regex yazılmaya çalışılırken Belki Google'da bu bulacaksınız değil bir alt içerir. Anlamak için bana biraz zaman ayırdı, bu yüzden paylaşacağım:

Bir dize verildi: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

<span>Alt dizeyi "kötü" içermeyen etiketleri eşleştirmek istiyorum .

/<span(?:(?!bad).)*?>eşleşecek <span class=\"good\">ve <span class=\"ugly\">.

İki parantez (katman) kümesi olduğuna dikkat edin:

  • En içteki şey negatif ileriye yöneliktir (bir yakalama grubu değildir)
  • En dıştaki Ruby tarafından yakalama grubu olarak yorumlandı, ancak biz bir yakalama grubu olmasını istemiyoruz, bu yüzden ekledim?: Başında ve artık bir yakalama grubu olarak yorumlanmıyor.

Ruby'de Demo:

s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]

0

İle ConyEdit , komut satırını kullanabilirsiniz cc.gl !/hede/Normal ifade eşlemeyi içeren veya komut satırını kullanmayan satırları almak için cc.dl /hede/Normal ifade eşlemeyi ihtiva silme hatlarına. Aynı sonuca sahipler.


0

Dize X içeren , ancak dize Y içermeyen bir satırı eşleştirmeye çalışıyorsanız için başka bir örnek eklemek istedim .

Örneğin, URL / dizgimizin hiçbir yerde " çikolata " içermediği sürece " lezzetli ikramlar " içerip içermediğini kontrol etmek istediğimizi varsayalım .

Bu normal ifade kalıbı işe yarar (JavaScript'te de çalışır)

^(?=.*?tasty-treats)((?!chocolate).)*$

(örnek olarak küresel, çok satırlı bayraklar)

Etkileşimli Örnek: https://regexr.com/53gv4

Maçlar

(Bu URL'ler "lezzetli ikramlar" içerir ve "çikolata" içermez)

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

Eşleşmiyor

(Bu URL'ler bir yerde "çikolata" içerir - bu nedenle "lezzetli ikramlar" içermelerine rağmen eşleşmezler)

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts
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.