2010-10-03 11 views
38

Dla regex jaka jest składnia wyszukiwania, ale nie obejmuje? Kinda lubią:Regex do czasu, ale nie włączając

Haystack: 
The quick red fox jumped over the lazy brown dog 

Expression: 
.*?quick -> and then everything until it hits the letter "z" but do not include z 

Odpowiedz

104

Wyraźna sposób powiedzenia "szukaj aż X ale nie w tym X" to:

(?:(?!X).)* 

gdzie X może być dowolne wyrażenie regularne.

W twoim przypadku, choć to może być przesada - tu najprostszym sposobem byłoby

[^z]* 

ten będzie pasował do niczego z wyjątkiem z a więc zatrzymują się tuż przed kolejnym z.

Tak .*?quick[^z]* będzie pasować do The quick fox jumps over the la.

jednak tak szybko, jak masz więcej niż jeden prosty list, aby zwrócić uwagę, (?:(?!X).)* wchodzi w grę, na przykład

(?:(?!lazy).)* - pasuje do niczego, aż do początku słowa lazy.

Używa się w tym celu pewnej wartości ujemnej do przodu.

.*?quick(?:(?!lazy).)* będzie pasować do The quick fox jumps over the.

Objaśnienie:

(?:  # Match the following but do not capture it: 
(?!lazy) # (first assert that it's not possible to match "lazy" here 
.   # then match any character 
)*   # end of group, zero or more repetitions. 

Ponadto, szukając słów kluczowych, warto otoczyć je ze słowem kotew brzegowych: \bfox\b będzie pasował tylko kompletny słowo fox ale nie lisa w foxy.

Uwaga

Jeżeli tekst ma być dopasowana może również zawierać linebreaks, trzeba będzie ustawić „kropka” pasuje do wszystkich opcji silnika regex. Zwykle można to osiągnąć, dodając do regex (?s), ale to nie działa we wszystkich silnikach regex (szczególnie w JavaScript).

Alternatywne rozwiązanie:

W wielu przypadkach można również wykorzystać prostszy, bardziej czytelny rozwiązanie, które używa kwantyfikator leniwy. Dodając ? do * kwantyfikatorem, będzie starał się dopasować jak kilka znaków, jak to możliwe od aktualnej pozycji:

.*?(?=(?:X)|$) 

będzie pasował dowolną liczbę znaków, zatrzymując się tuż przed X (którym może być każdy regex) lub koniec ciągu (jeśli X nie pasuje). Możesz również ustawić opcję "dot match all", aby to działało.(Uwaga: dodałem grupę non-przechwytywania wokół X w celu niezawodnego odizolowania go od przemienności)

+0

+1 Naprawdę ładne odpowiedź, niestety nie działa z 'grep', ale to [odpowiedź] (http://stackoverflow.com/a/5979402/ 354831). –

+0

@AlexandreLavoie: Interesujące. Dlaczego drugi powinien działać, a nie ten? Oba używają asercji z wyprzedzeniem. Być może dzieje się tak tylko z powodu grupy "(?: ...)" nie przechwytującej? Czy działa z '((?! X).) *'? –

+1

Naprawdę nie wiem, nie jestem ekspertem od regex ani grep. Używałem 'grep' do filtrowania żądań dla tylko jednej bazy danych z mysql bin transformet w sql. Oto bestia: 'grep -Po" (? S) użyj database_to_keep (. *?) (? =^Use) "mysql-bin.000045.sql> filtered.sql' –

0

Spróbuj

(.*?quick.*?)z 
+0

Obejmuje to "z" w meczu, który jest dokładnie tym, czego pytający chce uniknąć. Być może regex ma być terminem w "|" alternatywny, a alternatywne wyrażenie regularne służy do wykonywania wielu dopasowań. Jeśli "z" jest początkiem ciągu, który zostałby dopasowany przez ** inny ** termin w alternatywnym, to ten mecz zostanie utracony, ponieważ "z" jest już zużywane przez bieżące dopasowanie. –

5

lookahead regex syntax może pomóc Ci osiągnąć swój cel. Zatem regex dla przykładu jest

.*?quick.*?(?=z) 

I ważne jest, aby zauważyć .*? leniwe dopasowanie przed (?=z) uprzedzona: wyrażenie dopasowuje podciąg aż pierwszej wystąpienia litery z.

Oto przykładowy kod C#:

const string text = "The quick red fox jumped over the lazy brown dogz"; 

string lazy = new Regex(".*?quick.*?(?=z)").Match(text).Value; 
Console.WriteLine(lazy); // The quick red fox jumped over the la 

string greedy = new Regex(".*?quick.*(?=z)").Match(text).Value; 
Console.WriteLine(greedy); // The quick red fox jumped over the lazy brown dog 
Powiązane problemy