6 Stimmen

Lookahead und nicht-erfassende reguläre Ausdrücke

Ich versuche, den lokalen Teil einer E-Mail-Adresse vor dem @-Zeichen mit abzugleichen:

LOCAL_RE_NOTQUOTED = """
((
\w         # alphanumeric and _
| [!#$%&'*+-/=?^_`{|}~]          # special chars, but no dot at beginning
)
(
\w         # alphanumeric and _
| [!#$%&'*+-/=?^_`{|}~]          # special characters
| ([.](?![.])) # negative lookahead to avoid pairs of dots. 
)*)
(?<!\.)(?:@)           # no end with dot before @
"""

Testen mit:

re.match(LOCAL_RE_NOTQUOTED, "a.a..a@", re.VERBOSE).group()

gibt:

'a.a..a@'

Warum ist die @ in der Ausgabe gedruckt, obwohl ich eine nicht-erfassende Gruppe verwende (?:@) ?

Testen mit:

 re.match(LOCAL_RE_NOTQUOTED, "a.a..a@", re.VERBOSE).groups()

gibt:

('a.a..a', 'a', 'a', None)

Warum weist die Regex die Zeichenfolge mit einem Punktpaar nicht zurück? '..' ?

12voto

Tim Pietzcker Punkte 311448

Sie verwechseln nicht fangende Gruppen (?:...) und Vorausschau-Behauptungen (?=...) .

Erstere nehmen an dem Spiel teil (und sind somit Teil der match.group() die die gesamte Übereinstimmung enthält), sie erzeugen nur keinen Rückverweis ( $1 usw. zur späteren Verwendung).

Das zweite Problem (Warum ist der doppelte Punkt gleich?) ist etwas schwieriger. Der Grund dafür ist ein Fehler in Ihrer Regex. Wenn Sie schreiben (gekürzt, um es auf den Punkt zu bringen)

[+-/]

Sie schrieben "Ordnen Sie ein Zeichen zwischen + y / und in ASCII steht der Punkt genau zwischen ihnen (ASCII 43-47: +,-./ ). Daher stimmt die erste Zeichenklasse mit dem Punkt überein, und die Vorausschau-Behauptung wird nie erreicht. Sie müssen den Bindestrich am Ende der Zeichenklasse platzieren, um ihn als buchstäblichen Bindestrich zu behandeln:

((
\w         # alphanumeric and _
| [!#$%&'*+/=?^_`{|}~-]          # special chars, but no dot at beginning
)
(
\w         # alphanumeric and _
| [!#$%&'*+/=?^_`{|}~-]          # special characters
| ([.](?![.])) # negative lookahead to avoid pairs of dots. 
)*)
(?<!\.)(?=@)           # no end with dot before @

Und wenn Sie diese Logik anwenden wollen, können Sie sie natürlich ein wenig straffen:

^(?!\.)                   # no dot at the beginning
(?:
[\w!#$%&'*+/=?^_`{|}~-]   # alnums or special characters except dot
| (\.(?![.@]))            # or dot unless it's before a dot or @ 
)*
(?=@)                     # end before @

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X