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)
+1 Naprawdę ładne odpowiedź, niestety nie działa z 'grep', ale to [odpowiedź] (http://stackoverflow.com/a/5979402/ 354831). –
@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).) *'? –
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' –