Regex do, ale nie włącznie

81

Jaka jest składnia wyszukiwania do wyrażenia regularnego, ale bez uwzględniania tego wyrażenia? Coś jak:

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
NoodleOfDeath
źródło

Odpowiedzi:

162

Dosłowny sposób powiedzenia „szukaj do, Xale nie uwzględniaj X” to:

(?:(?!X).)*

gdzie Xmoże być dowolne wyrażenie regularne.

W twoim przypadku może to być przesada - tutaj najłatwiej byłoby

[^z]*

Dopasuje to wszystko oprócz zi dlatego zatrzyma się tuż przed następnym z.

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

Jednak na przykład, gdy masz więcej niż jedną prostą literę, na którą musisz zwrócić uwagę, (?:(?!X).)*w grę wchodzi

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

To jest użycie asercji wyprzedzającej , a dokładniej negatywnej.

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

Wyjaś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, podczas wyszukiwania słów kluczowych, możesz chcieć otoczyć je kotwicami granic słów: \bfox\bdopasuje tylko całe słowo, foxale nie będzie zawierał listu foxy.

Uwaga

Jeśli tekst, który ma zostać dopasowany, może również zawierać podziały wierszy, musisz ustawić opcję „kropka pasuje do wszystkich” w Twoim silniku wyrażeń regularnych. Zwykle można to osiągnąć, poprzedzając (?s)wyrażenie regularne, ale to nie działa we wszystkich silnikach wyrażeń regularnych (zwłaszcza JavaScript).

Alternatywne rozwiązanie:

W wielu przypadkach można również użyć prostszego, bardziej czytelnego rozwiązania, które wykorzystuje leniwy kwantyfikator. Dodając a ?do *kwantyfikatora, spróbuje dopasować jak najmniej znaków z bieżącej pozycji:

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

dopasuje dowolną liczbę znaków, zatrzymując się tuż przed X(może to być dowolne wyrażenie regularne) lub na końcu ciągu (jeśli Xnie pasuje). Aby to zadziałało, może być konieczne ustawienie opcji „kropka pasuje do wszystkich”. (Uwaga: dodałem grupę bez przechwytywania X, aby niezawodnie odizolować ją od naprzemienności)

Tim Pietzcker
źródło
+1 Naprawdę fajna odpowiedź, niestety nie działa grep, ale ta odpowiedź działa.
Alexandre Lavoie
@AlexandreLavoie: Interesujące. Dlaczego ten drugi miałby działać, a nie ten? Obie używają asercji wyprzedzających. Może to tylko z powodu grupy (?:...)bez przechwytywania? Czy to działa ((?!X).)*?
Tim Pietzcker,
1
Naprawdę nie wiem, nie jestem ekspertem od regexów ani grepem. Używałem grepdo filtrowania żądań tylko jednej bazy danych z transformetu mysql bin w sql. Oto bestia:grep -Po "(?s)use database_to_keep(.*?)(?=^use)" mysql-bin.000045.sql > filtered.sql
Alexandre Lavoie
Wygląda na konflikt bash od kiedy nacisnąłem Upklawisz, ostatnie polecenie nie jest tym, którego użyłem:grep -Po "(?s)use database_to_keep(.*?)(?:(?!^use).)*" mysql-bin.000045.sql > filtered.sql
Alexandre Lavoie
1
Dobry edytować @Tim, wystarczy dodać $alternatywny zamienić .*?(?=X)z.*?(?=X|$)
Wiktor Stribiżew
15

Składnia uprzedzona regex może pomóc Ci osiągnąć swój cel. Tak więc wyrażenie regularne dla twojego przykładu to

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

I ważne jest, aby zwrócić uwagę na .*?leniwe dopasowywanie przed (?=z)lookahead: wyrażenie dopasowuje podłańcuch aż do pierwszego wystąpienia zlitery.

Oto przykładowy kod w języku 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
Igor Kustov
źródło
0

Spróbuj tego

(.*?quick.*?)z
Maks
źródło
3
Obejmuje to „z” w meczu, czyli dokładnie to, czego pytający chce uniknąć. Być może wyrażenie regularne ma być wyrażeniem w „|” alternatywa, a to alternatywne wyrażenie regularne jest używane do wykonywania wielu dopasowań. Jeśli „z” jest początkiem ciągu, który zostałby dopasowany przez inny termin w alternatywie, to dopasowanie zostanie utracone, ponieważ „z” jest już wykorzystane przez bieżące dopasowanie.
Szczepan Hołyszewski 27.08.15