Składnia wyrażenia regularnego dla „nic nie pasuje”?

83

Mam silnik szablonów Pythona, który w dużym stopniu korzysta z wyrażenia regularnego. Używa konkatenacji, takich jak:

re.compile( regexp1 + "|" + regexp2 + "*|" + regexp3 + "+" )

Potrafię modyfikować poszczególne podciągi (regexp1, regexp2 itp.).

Czy jest jakieś małe i lekkie wyrażenie, które nic nie pasuje, a którego mogę użyć wewnątrz szablonu, w którym nie chcę żadnych dopasowań? Niestety, czasami do atomu wyrażenia regularnego dołączane jest „+” lub „*”, więc nie mogę użyć pustego ciągu - spowoduje to błąd „nic do powtórzenia”.

grigoryvp
źródło
3
Czy tytuł mógłby być lepiej sformułowany jako „Wyrażenie regularne, które nie pasuje do niczego”? Brak dopasowania oznacza pomyślne dopasowanie pustego ciągu.
BamaPookie

Odpowiedzi:

126

To nie powinno do niczego pasować:

re.compile('$^')

Więc jeśli zamienisz regexp1, regexp2 i regexp3 na '$ ^', znalezienie dopasowania będzie niemożliwe. Chyba że używasz trybu wieloliniowego.


Po kilku testach znalazłem lepsze rozwiązanie

re.compile('a^')

Nie da się dopasować i zawiedzie wcześniej niż poprzednie rozwiązanie. Możesz zastąpić dowolną inną postać, a dopasowanie zawsze będzie niemożliwe

Nadia Alramli
źródło
To na pewno nie pasuje do niczego i jest lekkie do przetworzenia przez silnik regexp? (nie chcę, aby moje
wyrażenia regularne zjadały
@Eye of hell. Powinien być lekki. To spróbuje dopasować koniec linii, po którym nastąpi początek linii. Co jest niemożliwe w jednej linii.
Nadia Alramli
1
Ale jest to oczywiście możliwe z wieloma wierszami (w zależności od tego, czy flaga jest włączona) - w przypadku rozwiązania, które działa niezależnie od tego, czy flaga jest włączona, czy nie, zobacz moją odpowiedź.
Peter Boughton
16
Wyrażenie regularne „$ ^” pasuje do pustego ciągu, przynajmniej w niektórych implementacjach. Drugi jest lepszy.
Roman Starkov
@romkyns Drugi nie pasuje do pustego ciągu w moim wywołaniu PyQt4 QtCore.QRegExp. Tak źle, że z pewnością byłoby lżejsze do wykonania.
Joël
44

(?!)powinien zawsze nie pasować. Jest to ujemne antycypowanie o zerowej szerokości. Jeśli to, co jest w nawiasach, pasuje, to całe dopasowanie kończy się niepowodzeniem. Biorąc pod uwagę, że nic w nim nie ma, nie uda mu się dopasować niczego (w tym niczego).

Chas. Owens
źródło
4
Racja, też zamierzałem to opublikować. To najlepszy sposób, jeśli twój język obsługuje lookahead. Podobnie (? =) Pasuje do każdego ciągu.
Brian Carper
16

Aby dopasować pusty ciąg - nawet w trybie wielowierszowym - możesz użyć \A\Z, więc:

re.compile('\A\Z|\A\Z*|\A\Z+')

Różnica polega na tym, że \Ai \Zsą początkiem i końcem ciągu , podczas gdy ^i $te mogą pasować do początku / końca linii , więc $^|$^*|$^+potencjalnie mogą pasować do ciągu zawierającego znaki nowej linii (jeśli flaga jest włączona).

Aby niczego nie dopasować (nawet pustego ciągu), po prostu spróbuj znaleźć treść przed jego początkiem, np .:

re.compile('.\A|.\A*|.\A+')

Ponieważ żadne znaki nie mogą występować przed \ A (z definicji), to zawsze nie pasuje.

Peter Boughton
źródło
Twój wygląda ładniej niż mój, ponieważ zakładam, że wyjdzie szybciej niż przy użyciu końca linii.
ShuggyCoUk
Peter, używasz \ z (małe litery), podczas gdy mój kieszonkowy przewodnik po Pythonie mówi mi, że asercja końca łańcucha to \ Z (duża litera) ?!
ThomasH
ThomasH, oba są końcami łańcucha, ale wersja pisana dużymi literami pozwala na końcową linię nowej linii, podczas gdy mała - nie.
Peter Boughton,
Mh, ciekawe, nigdzie to nie zostało udokumentowane. Również, re.search ("boo \ z", "fooboo") nie zwraca obiektu dopasowania, podczas gdy re.search ("boo \ Z", "fooboo) to robi. Zamiast tego re.search (" boo \ z "," foobooz ") pasuje, co świadczy o tym, że '\ z' jest po prostu interpretowane jako 'z', prawda ?! (To jest w Pythonie 2.6).
ThomasH
Ach przepraszam, myślałem, że Python to PCRE, ale okazuje się, że jest kilka różnic, a to jest jedna z nich. (Zobacz 'Anchors' na regular-expressions.info/refflavors.html )
Peter Boughton
4

Może '.{0}'?

Steef
źródło
1

Możesz użyć
\z..
To jest bezwzględny koniec łańcucha, po którym następują dwa dowolne elementy

Jeśli +lub *zostanie przypięty na końcu, to nadal działa, odmawiając dopasowania czegokolwiek

ShuggyCoUk
źródło
Dlaczego dwie z niczego? W \zprzeciwieństwie do IIRC nie zezwala na końcowe znaki nowej linii \Z, więc czy jeden nie wystarczy? Lub to dziwna obrona przed *(dlaczego się przed tym
bronisz
0

Lub użyj funkcji składania list, aby usunąć bezużyteczne wpisy wyrażeń regularnych i połączyć je wszystkie razem. Coś jak:

re.compile('|'.join([x for x in [regexp1, regexp2, ...] if x != None]))

Pamiętaj jednak, aby dodać komentarze obok tego wiersza kodu :-)

Mike Miller
źródło