Ich habe alle verwandten Beiträge gelesen und das Internet durchforstet, aber das schlägt mich wirklich.
Ich habe einen Text mit einem Datum.
Ich möchte das Datum erfassen, aber nicht, wenn ihm ein bestimmter Satz vorangestellt ist.
Eine einfache Lösung besteht darin, meiner RegEx ein negatives Lookbehind hinzuzufügen.
Hier ein paar Beispiele (mit findall).
Ich möchte nur das Datum erfassen, wenn nicht die Phrase "ab" vorangestellt ist.
19-2-11
etwas etwas 15-4-11
so und so von 29-5-11
Hier ist mein regulärer Ausdruck:
%Vor%Erwartete Ergebnisse:
['19-2-11']
['15 -4-11 ']
[]
Tatsächliche Ergebnisse:
['19-2-11']
['15 -4-11 ']
['9-5-11']
Beachten Sie, dass 9 nicht 29 ist. Wenn ich \d{1,2}
auf etwas Solides wie \d{2}
im ersten Muster ändere:
Dann bekomme ich meine erwarteten Ergebnisse. Natürlich ist das nicht gut, weil ich zweistellige Tage sowie einstellige Tage zusammenstellen möchte.
Offenbar ist mein negativer Lookbehind sehr gierig - mehr als meine Datenerfassung, also stiehlt er eine Ziffer und versagt. Ich habe alles versucht, um die Gier zu korrigieren, die ich mir vorstellen kann, aber ich weiß einfach nicht, wie ich das beheben kann.
Ich möchte, dass meine Datumserfassung mit der größten Gier übereinstimmt, und dann wird mein negativer Lookbehind angewendet. Ist das möglich? Mein Problem schien eine gute Verwendung von negativen Lookbehinds zu sein und nicht übermäßig kompliziert. Ich bin mir sicher, dass ich es auf eine andere Weise schaffen könnte, wenn ich es tun müsste, aber ich würde gerne lernen, wie das geht.
Wie mache ich Pythons negativen Look weniger gierig?
Der Grund ist nicht, weil Lookbehind gierig ist. Dies geschieht, weil die Regex-Engine versucht, das Muster an jeder möglichen Position abzugleichen.
Es geht weiter durch den Ausdruck such and such as of 29-5-11
, der zuerst mit (?<!as of )
übereinstimmt, aber nicht mit \d{1,2}
.
Aber dann findet die Engine die selbe in der Position such and such as of !29-5-11
(markiert mit !
). Aber hier stimmt (?<!as of )
nicht überein.
Und es geht weiter zur nächsten Position: such and such as of 2!9-5-11
. Wo es mit (?<!as of )
und dann mit \d{1,2}
übereinstimmt.
Wie man es vermeidet?
Die allgemeine Lösung besteht darin, das Muster so klar wie möglich zu formulieren .
In diesem Fall würde ich die Ziffer mit dem notwendigen Leerzeichen oder dem Anfang der Zeichenfolge voranstellen.
%Vor%Die Lösung von Mark Byers ist auch sehr gut.
Ich denke, es ist sehr wichtig zu verstehen, warum sich die Regex-Engine so verhält und unerwünschte Ergebnisse liefert.
Übrigens funktioniert die obige Lösung nicht, wenn es zwei oder mehr Leerzeichen gibt.
Es funktioniert nicht, weil die erste Position hier such and such as of ! 29-5-11
mit dem oben genannten Muster übereinstimmt.
Was kann getan werden, um es zu vermeiden?
Leider unterstützt lookbehind in Python die Regex-Engine nicht die Quantifizierer +
oder *
.
Ich denke, die einfachste Lösung wäre, sicherzustellen, dass es keine Leerzeichen vor (?:^|\s+)
gibt (so dass alle Leerzeichen von (?:^|\s+)
unmittelbar nach einem Nicht-Leerzeichen-Text konsumiert werden) (und falls der Text as of
ist, beende) Vorrücken und zurück zur nächsten Startposition gehen und die Suche an der nächsten Position des gesuchten Textes erneut starten).
Das hat nichts mit Gier zu tun. Gierigkeit ändert sich nicht, ob ein regulärer Ausdruck übereinstimmt oder nicht - er ändert nur die Reihenfolge, in der die Suche ausgeführt wird. Das Problem hierbei ist, dass Ihr regulärer Ausdruck spezifischer sein muss, um unerwünschte Übereinstimmungen zu vermeiden.
Um es zu beheben, könnten Sie eine Wortgrenze vor dem Match benötigen:
%Vor%Eine einfache Lösung wäre es, alle Zeilen, die mit 'ab' übereinstimmen, zu entfernen, bevor die Regex verwendet wird, um die Daten zu isolieren.