Seite 1 von 1

Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 16:46
von api
Hallo zusammen,

ich möchte gerne die Inhalte zwischen den eckigen Klammern auslesen. Dazu habe ich folgendes geschrieben:

Code: Alles auswählen

import re

line = "error in date[02.02.2017] between line[487182, 487190]: invalid!"

bracket_content = re.findall(r"\[([a-zA-Z0-9_]+)\]", line)

print bracket_content
Die Ausgabe ist:
Was mache ich falsch bzw. übersehe ich?

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 17:31
von api
Jetzt hab ich es selbst herausgefunden... (in grün)

So muss die regex-Zeile lauten: bracket_content = re.findall(r"\[([a-zA-Z0-9_., ]+)\]", line)

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 17:59
von snafu

Code: Alles auswählen

re.findall(r'(?<=\[).*?(?=\])', line)
Das arbeitet mit Lookahead und Lookbehind. Ist daher leider auch entsprechend schlecht lesbar.

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 20:20
von DasIch
Das ist aber reichlich umständlich. Wenn du dir den String anschaust, also mit den eignen Augen, suchst du auch nach der öffnenden Klammern und schaust dann ob danach ein oder mehrere Buchstaben, Zahlen, Unterstriche, Punkte oder Kommas auftauchen, gefolgt von einer schliessenden Klammer? Mit deiner Anforderung stimmt dass zumindest nicht überein.

Wie wäre es einfach zu schauen ob eine Klammer auftaucht, gefolgt von irgendwas was keine schliessende Klammer ist, also dem Inhalt, gefolgt von der schliessenden Klammer?

Code: Alles auswählen

>>> import re
>>> line = "error in date[02.02.2017] between line[487182, 487190]: invalid!"
>>> re.findall(r'\[([^\]]+)\]', line)

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 20:46
von Sirius3
@DasIch: noch einfacher wird es durch die nicht-gefräßige Variante von `*`:

Code: Alles auswählen

re.findall(r'\[(.*?)\]', line)

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 21:01
von DasIch
Das ist kein regulärer Ausdruck mehr und benötigt Backtracking.

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 22:19
von snafu
Sirius3 hat geschrieben:@DasIch: noch einfacher wird es durch die nicht-gefräßige Variante von `*`:

Code: Alles auswählen

re.findall(r'\[(.*?)\]', line)
Das ist sogar noch besser als mein Lookbehind / Lookahead, da relativ gut lesbar. :)

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 22:24
von snafu
DasIch hat geschrieben:Das ist kein regulärer Ausdruck mehr und benötigt Backtracking.
Nur aus Interesse: Warum wird hier Backtracking benötigt? Ob ich ab dem Auftauchen eines [ alle Folgezeichen einsammle *solange kein* ] kommt (dein Ansatz) oder ob ich die Zeichen einsammle *bis* ein ] kommt (non-greedy Ansatz mit innerer Gruppe), ist das nicht letztlich genau das Gleiche?

Re: Regular expression funktioniert so nicht

Verfasst: Donnerstag 2. Februar 2017, 23:47
von snafu
Konnte es mir anhand der hier anführten Erklärungen selbst (hoffentlich korrekt) erklären: Eine Regex-Engine probiert stumpf schrittweise die einzelnen Bestandteile des regulären Ausdrucks durch. Das bedeutet, bei einem regulären Ausdruck abc (wobei a, b, und c für einen beliebigen Teilausdruck stehen) probiert die Engine zuerst, ob a matcht, bei Erfolg dann ob ab matcht und bei Erfolg dann ob abc matcht. Bei \[.*\] (habe non-greedy mal außen vor gelassen) würde die Engine also erst \[ (1) suchen, bei Erfolg dann \[.* (2) und bei Erfolg dann \[.*\] (3). Das wäre wegen Schritt 2 recht übel, was die Laufzeit angeht, weil dabei eben nicht gestoppt wird, wenn das ] auftaucht, da dieser dritte Schritt in dem Fall noch gar nicht beachtet wird. Vielmehr wird erstmal stumpf bis zum Ende probiert (.* = beliebige Anzahl beliebiger Zeichen) und sich danach per Backtracking "umständlich" der korrekten Zeichenkette angenähert. Beim Vorschlag von DasIch hingegen wird nicht über das Ziel hinausgeschossen, da [^\]]+ für alle Zeichen außer dem ] matcht und dies wegen dem + nur bis zum ersten Failure wiederholt wird. Danach geht er sofort zum nächsten Teilausdruck über. Ist das so richtig erklärt?