Jak „odwrócić dopasowanie” za pomocą wyrażenia regularnego?

112

Używam RegexBuddy, ale i tak mam z tym kłopoty: \

Przetwarzam wiersz po wierszu plik. Zbudowałem „model liniowy”, aby dopasować się do tego, czego chcę.

Teraz chciałbym wykonać odwrotne dopasowanie ... tj. Chcę dopasować wiersze, w których znajduje się ciąg 6 liter, ale tylko jeśli te sześć liter to nie Andrea , jak mam to zrobić?


EDYCJA: Napiszę program, który używa tego wyrażenia regularnego, jeszcze nie wiem, czy w pythonie czy php, robię to najpierw, aby nauczyć się jakiegoś wyrażenia regularnego :) Są różne typy linii, chciałem użyć wyrażenia regularnego aby wybrać typ, który mnie interesuje. Kiedy już mam te wiersze, muszę zastosować inny filtr, aby nie dopasować znanej wartości, potrzebuję wszystkich innych, a nie to. (?! Nie-poszukiwane) działa całkiem nieźle, dziękuję. :-)

Mam nadzieję, że to wyjaśnia pytanie :)

Andrea Ambu
źródło
Wygląda na to, że lepiej byłoby podać nam więcej informacji o tym, co robisz, i sprawdzić, czy ktoś może zaoferować alternatywne rozwiązanie. Zazwyczaj próba przeanalizowania całego pliku przez skonstruowanie wyrażenia regularnego pasującego do każdej linii jest dość skomplikowaną trasą :)
Dan

Odpowiedzi:

70
(?!Andrea).{6}

Zakładając, że Twój silnik regexp obsługuje ujemne wybiegania w przód.

Edycja: ... a może wolisz użyć [A-Za-z]{6}zamiast.{6}

Edytuj (ponownie): Zwróć uwagę, że patrzenie w przód i w tył zazwyczaj nie są właściwym sposobem „odwrócenia” dopasowania wyrażenia regularnego. Wyrażenia regularne nie są tak naprawdę skonfigurowane do przeprowadzania dopasowań negatywnych, pozostawiają to w jakimkolwiek języku, w którym ich używasz.

Dan
źródło
Musisz dodać ^, którego używa @Vinko Vrsalovic, aby nie pasowało do „ndrea \ n”
bdukes
2
. nie dopasowuje \ n domyślnie (niektóre języki [np. Perl] pozwalają na włączenie tego zachowania, ale domyślnie. dopasowuje wszystko ALE \ n).
Dan
1
(plus, OP nigdy nie wspominał, że struna musi wystąpić na początku linii)
Dan
1
co masz na myśli dla OP?
Andrea Ambu
1
Andrea: OP oznacza „oryginalny plakat”, więc mówiłem o tobie :)
Dan,
47

W przypadku Python / Java,

^(.(?!(some text)))*$

http://www.lisnichenko.com/articles/javapython-inverse-regex.html

Dmytro
źródło
4
To nie działa. Myślisz o idiomie Tempered Greedy Token. ale kropka musi iść za wyprzedzeniem, a nie przed. Zobacz to pytanie . Ale takie podejście i tak jest przesadą w przypadku tego zadania.
Alan Moore
Nie wiem, w jakim języku jest napisane, ale działało jak urok w Sublime text, aby wyczyścić moje dane testowe. Dzięki!
Matthias dirickx
1
@AlanMoore Właściwie to prawie zadziała w tym przypadku użycia. Jeśli jednak some textrozpocznie wiersz, zwróci nieprawidłowy wynik.
Zenexer,
2
@Zenexer, o to mi chodziło. Jeśli kropka znajduje się za wyprzedzeniem zamiast przed, działa idealnie.
Alan Moore
Oto link, który wyjaśnia więcej. Nie rozumiem dlaczego ?!i nie tylko !.
Timo
21

Zaktualizowano dzięki opiniom Alana Moore'a

W PCRE i podobnych wariantach można faktycznie utworzyć wyrażenie regularne pasujące do dowolnego wiersza niezawierającego wartości:

^(?:(?!Andrea).)*$

Nazywa się to hartowanym żetonem chciwości . Wadą jest to, że nie działa dobrze.

Zenexer
źródło
1
To jest żeton zahartowanej chciwości w długiej formie. Wystarczy umieścić kropkę (lub [\s\S], co jest użyteczne tylko w JavaScript) po drugim uprzedzona i nie trzeba się pierwszy: ^(?:(?!Andrea).)*$.
Alan Moore
@AlanMoore Nice! Nie mogłem znaleźć żadnego ustalonego wzoru, który działałby w ten sposób, więc wymyśliłem własny. Zamiast przyjąć twoją odpowiedź, powinieneś podać ją jako własną.
Zenexer
W porządku, jest już wiele dobrych odpowiedzi. Zasługujesz na uznanie za samodzielne wymyślenie idiomu. Twoje zdrowie!
Alan Moore
Dlaczego sugerujesz użycie [\S\s]? OP mówi o pasujących liniach, które nie zawierają słowa „Andrea”. Nie chodzi o sprawdzanie, czy cały ciąg zawiera to słowo. Czy coś mi brakuje?
x-yuri
@ x-yuri myślę, że masz rację. Prawdopodobnie odpowiedziałem na pytanie, które zadałem, czy po raz pierwszy odwiedziłem tę stronę, ignorując rozbieżność. Moje połączenie nie jest jednak wystarczająco dobre, aby zaktualizować odpowiedź w tej chwili (<10 kbps)
Zenexer
11

Jakiego języka używasz? W tym przypadku znaczenie mają możliwości i składnia implementacji wyrażenia regularnego.

Możesz użyć antycypowania. Na przykładzie Pythona

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

Aby to przełamać:

(?! Andrea) oznacza „dopasuj, jeśli kolejnych 6 znaków nie jest„ Andrea ””; jeśli tak, to

\ w oznacza „znak słowa” - znaki alfanumeryczne. Jest to odpowiednik klasy [a-zA-Z0-9_]

\ w {6} oznacza dokładnie 6 znaków słów.

re.IGNORECASE oznacza, że ​​wykluczysz „Andrea”, „andrea”, „ANDREA” ...

Innym sposobem jest użycie logiki programu - użyj wszystkich linii, które nie pasują do Andrei i przeprowadź je przez drugie wyrażenie regularne, aby sprawdzić 6 znaków. Lub najpierw sprawdź co najmniej 6 znaków słów, a następnie sprawdź, czy nie pasuje do Andrea.

Hamish Downer
źródło
7

Negatywne stwierdzenie wyprzedzania

(?!Andrea)

To nie jest dokładnie odwrócone dopasowanie, ale jest to najlepsze, co można zrobić bezpośrednio za pomocą wyrażenia regularnego. Jednak nie wszystkie platformy je obsługują.

Vinko Vrsalovic
źródło
1
Dopóki pytający nie wyjaśni, nie widzę, żeby mecz zaczynał się na początku linii. Więc dlaczego ^?
Hamish Downer
Ponieważ zrozumiałem, że chciał sprawdzić na początku linii, zredagowałem podane wyjaśnienia
Vinko Vrsalovic
5

Jeśli chcesz to zrobić w RegexBuddy, istnieją dwa sposoby uzyskania listy wszystkich wierszy niepasujących do wyrażenia regularnego.

Na pasku narzędzi w panelu Test ustaw zakres testu na „Linia po linii”. Gdy to zrobisz, element Lista wszystkich wierszy bez dopasowań pojawi się pod przyciskiem Lista wszystkich na tym samym pasku narzędzi. (Jeśli nie widzisz przycisku Wyświetl wszystkie, kliknij przycisk Dopasuj na głównym pasku narzędzi).

W panelu GREP możesz zaznaczyć pola wyboru „oparte na wierszach” i „Odwróć wyniki”, aby uzyskać listę niepasujących wierszy w plikach, przez które przeglądasz.

Jan Goyvaerts
źródło
5

(?!jest przydatne w praktyce. Chociaż ściśle mówiąc, patrzenie w przyszłość nie jest wyrażeniem regularnym zdefiniowanym matematycznie.

Możesz ręcznie napisać odwrócone wyrażenie regularne.

Oto program do automatycznego obliczania wyniku. Jego wynik jest generowany maszynowo, co jest zwykle znacznie bardziej złożone niż pisanie ręczne. Ale wynik działa.

słabe
źródło
1

Właśnie wymyśliłem tę metodę, która może wymagać dużej ilości sprzętu, ale działa:

Możesz zastąpić wszystkie znaki, które pasują do wyrażenia regularnego, pustym ciągiem.

To jest oneliner:

notMatched = re.sub(regex, "", string)

Użyłem tego, ponieważ byłem zmuszony użyć bardzo złożonego wyrażenia regularnego i nie mogłem wymyślić, jak odwrócić każdą jego część w rozsądnym czasie.

To zwróci tylko wynik w postaci łańcucha, a nie żadnych dopasowanych obiektów!

Matthias Herrmann
źródło
-3

W perlu możesz to zrobić

proces ($ linia) if ($ linia = ~! / Andrea /);

phreakre
źródło
4
Ta składnia jest nieprawidłowa. Myślę, że masz na myśli proces ($ line), jeśli $ line! ~ / Andrea /
dland