Übrigens, da reguläre Sprachen (auch rationale Sprachen genannt) unter Komplementierung abgeschlossen sind, ist es immer möglich, einen regulären Ausdruck (auch rationalem Ausdruck genannt) zu finden, der einen anderen Ausdruck negiert. Aber nicht viele Tools implementieren dies.
Vcsn unterstützt diesen Operator (den es als {c}
, postfix, bezeichnet).
Zuerst definieren Sie den Typ Ihrer Ausdrücke: Labels sind Buchstaben (lal_char
), die beispielsweise aus a
bis z
auswählen (Die Definition des Alphabets bei der Arbeit mit Komplementierung ist natürlich sehr wichtig) und der "Wert", der für jedes Wort berechnet wird, ist einfach ein Boolescher Wert: true
das Wort wird akzeptiert, false
abgelehnt.
In Python:
In [5]: import vcsn
c = vcsn.context('lal_char(a-z), b')
c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}
dann geben Sie Ihren Ausdruck ein:
In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c
konvertiere diesen Ausdruck in einen Automaten:
In [7]: a = e.automaton(); a
schließlich konvertiere diesen Automaten wieder in einen einfachen Ausdruck.
In [8]: print(a.expression())
\e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*
wo +
normalerweise als |
dargestellt wird, \e
das leere Wort bezeichnet und [^]
normalerweise als .
(beliebiges Zeichen) geschrieben wird. Also, mit ein wenig Umformung ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*
.
Sie können dieses Beispiel hier sehen und Vcsn online ausprobieren dort.
105 Stimmen
Wahrscheinlich ein paar Jahre zu spät, aber was ist falsch mit:
([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*
? Die Idee ist einfach. Fahren Sie mit dem Abgleich fort, bis Sie den Beginn des unerwünschten Strings sehen, und gleichen Sie dann nur in den N-1 Fällen ab, in denen der String nicht abgeschlossen ist (wobei N die Länge des Strings ist). Diese N-1 Fälle sind "h gefolgt von nicht-e", "he gefolgt von nicht-d" und "hed gefolgt von nicht-e". Wenn es Ihnen gelungen ist, diese N-1 Fälle zu bestehen, haben Sie den unerwünschten String erfolgreich nicht abgeglichen, sodass Sie erneut mit der Suche nach[^h]*
beginnen können.427 Stimmen
@stevendesu: Versuche dies für 'ein-sehr-sehr-langes-Wort' oder noch besser einen halben Satz. Viel Spaß beim Tippen. Übrigens, es ist fast unleserlich. Weiß nicht über den Leistungseinfluss.
14 Stimmen
@PeterSchuetze: Sicher ist es nicht schön für sehr sehr lange Wörter, aber es ist eine praktikable und korrekte Lösung. Obwohl ich keine Tests zur Leistung durchgeführt habe, würde ich mir vorstellen, dass es nicht allzu langsam ist, da die meisten nachfolgenden Regeln ignoriert werden, bis Sie ein h sehen (oder den ersten Buchstaben des Wortes, Satzes usw. sehen). Und Sie könnten den Regex-String für lange Zeichenfolgen leicht mithilfe iterativer Konkatenation generieren. Wenn es funktioniert und schnell generiert werden kann, ist Lesbarkeit wichtig? Dafür sind Kommentare da.
66 Stimmen
@stevendesu: Ich bin noch später dran, aber diese Antwort ist fast komplett falsch. Zum einen verlangt sie, dass das Subjekt "h" enthält, was es nicht sollte, da die Aufgabe lautet, "Zeilen abzugleichen, die ein bestimmtes Wort nicht enthalten". Lassen Sie uns annehmen, dass Sie die innere Gruppe optional machen wollten und dass das Muster verankert ist:
^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$
. Dies scheitert, wenn Instanzen von "hede" von teilweisen Instanzen von "hede" wie in "hhede" vorausgehen.19 Stimmen
Diese Frage wurde zum Stack Overflow Regular Expression FAQ hinzugefügt, unter "Advanced Regex-Fu".
0 Stimmen
Verwandt: Regex: Übereinstimmung durch Ausschluss, ohne Vorwärtsblick - ist das möglich?