Regex: multiple Gruppen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Hallo,

ich probiere schon eine ganze Weile mit Hilfe eines entsprechenden regulären Ausdrucks substrings aus einem Suchtext zu extrahieren.

Beispielstring:
'123a111a222a3333a55432'

Gefunden werden sollen '111, '222', '3333', also die substrings zwischen dem delimiter 'a'. Wahrscheinlich ist die Lösung ganz einfach, aber ich komme im Moment nicht drauf...
Mein Versuch:

Code: Alles auswählen

m = re.match( '.*a(.*)a(.*)a(.*)a.*', '123a2222a4444a555a65a43' )
if m:
    print m.groups()

Das Problem bei meiner Lösung ist, dass ich die genaue Anzahl der substrings wissen muss, um alle Lösungen zu finden. Im Suchstring ist die Anzahl der substrings aber unbestimmt (kann auch 0 sein).

Vielen Dank,

lunas
Zuletzt geändert von lunas am Samstag 2. Dezember 2006, 11:56, insgesamt 1-mal geändert.
helmut
User
Beiträge: 57
Registriert: Mittwoch 2. November 2005, 07:45
Wohnort: Dormagen

Hallo lunas,

vielleicht reicht Dir ja schon "split":

Code: Alles auswählen

python[EIN 6]> s='123a111a222a333'
python[EIN 7]> s.split('a')
      [AUS 7]> ['123', '111', '222', '333']
Gruss, helmut
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Hallo helmut,

ich glaube nicht, dass es reicht, denn ich brauche eigentlich nur die vom delimiter (der übrigens eigentlich ein längerer string ist, aber zur Vereinfachung als 'a' gewählt wurde) eingeschlossenen Zeichen.
'123' und '333' (in deinem Bsp.) sollten also demnach nicht im Zielarray enthalten sein.

Aber trotzdem danke für den Tip. Die split methode kannte ich bisher noch nicht...
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

lunas hat geschrieben:ich brauche eigentlich nur die vom delimiter eingeschlossenen Zeichen.
Hi Lunas!

Willkommen im Python-Forum!

Eine Liste kannst du "slicen". Du kannst also jedes einzelne Element oder eine Elementgruppe aus der Liste auswählen. So kannst du auch eine Auswahl herausnehmen, in der gezielt das erste und das letzte Element fehlen.:

Code: Alles auswählen

>>> s = "123a111a222a333"
>>> s.split("a")[1:-1]
['111', '222']
>>> 
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mit ``re`` kannst du auch mehrere Zeichen als Splitter verwenden:

Code: Alles auswählen

>>> s = "ddda111b222c333a444addd"
>>> import re
>>> li = re.split("[abc]", s)
>>> li
['ddd', '111', '222', '333', '444', 'ddd']
>>> li[1:-1]
['111', '222', '333', '444']
>>>

Oder auch einzelne Wörter:

Code: Alles auswählen

>>> s = "dddaua111buta222cuta333aua444auaddd"
>>> li = re.split("aua|buta|cuta", s)
>>> li
['ddd', '111', '222', '333', '444', 'ddd']
>>> li[1:-1]
['111', '222', '333', '444']
>>>
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Nur leider ist es nicht gewiss, dass der erste und letzte string ausgeschlossen werden sollen. Ich möchte auch ungern testen, ob der delimiter am Anfang oder am Ende steht... Was ich suche ist ein möglichst knapper Ausdruck, der möglichst allgemein gehalten ist.

Am Ende möchte ich verschiedene Dateien nach verschiedenen Mustern durchsuchen. Dafür würde es am einfachsten sein, durch ein Array von patterns zu iterieren und ständig die gleichen Funktionen (nämlich match und group) zu nutzen... Der Algorithmus soll also gleich sein und nur im pattern variieren.

Lässt sich das etwa nicht machen?
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

lunas hat geschrieben:Nur leider ist es nicht gewiss, dass der erste und letzte string ausgeschlossen werden sollen.
Wieso nicht?

Wenn du alle Teile haben willst, die z.B. von ABC umschlossen sind, bekommst du beim Eingabestring

"fooABCbarABCbazABCquux" als Ergebnis ['foo', 'bar', 'baz', 'quux']

"bar" und "baz" sind die gesuchten.

bei "ABCfooABCbarABC" bekommst du ['', 'foo', 'bar', '']. Auch hier musst du nur den ersten und letzten Wegschneiden.
[1:-1] funktioniert also.

Wenn ABC sowas wie Anführungszeichen seien sollen, also du bei

"ABCfooABCbarABCbazABC" nur foo und baz zurückbekommen willst, nimm doch findall bzw. finditer:

Code: Alles auswählen

for x in re.finditer("ABC.*?ABC", "ABCfooABCbarABCbazABC"):
  print x # ABCfooABC, ABCbazABC
Wichtig ist das Fragezeichen nach dem *, damit der * non-greedy wird.
Zuletzt geändert von Joghurt am Samstag 2. Dezember 2006, 13:10, insgesamt 1-mal geändert.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

lunas hat geschrieben:Nur leider ist es nicht gewiss, dass der erste und letzte string ausgeschlossen werden sollen. Ich möchte auch ungern testen, ob der delimiter am Anfang oder am Ende steht...
Hi lunas!

Du machst dir hier sicher keine Freunde, wenn du die hier gezeigten Beispiel nicht ausprobierst. :roll:

Code: Alles auswählen

>>> s = "addda111b222c333a444addda"
>>> s.split("a")
['', 'ddd', '111b222c333', '444', 'ddd', '']
>>> s.split("a")[1:-1]
['ddd', '111b222c333', '444', 'ddd']
>>> 
Du kannst mit ``re`` keine überlappenden Bedingungen angeben. Ein "gib alles Zurück, was in ``a`` eingeschlossen ist!" funktioniert nicht, bei so einem String: "a123a123a".
Der Pattern "a(.*?)a" markiert "a123a" als "erledigt". Die Nächste Suche wird also nur mehr "123a" als Basis haben. Deshalb wird das zweite "123" nicht mehr gefunden. Du müsstest die Suche mehrmals durchlaufen. Jedes mal mit einem, etwas kürzeren String...

Sei froh, wenn du dein Problem also mit ``split`` lösen kannst. Wenn nicht, dann wird es komplizierter.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

lunas hat geschrieben:Nur leider ist es nicht gewiss, dass der erste und letzte string ausgeschlossen werden sollen.
Wonach wird das denn entschieden?
Ich möchte auch ungern testen, ob der delimiter am Anfang oder am Ende steht... Was ich suche ist ein möglichst knapper Ausdruck, der möglichst allgemein gehalten ist.
Warum? Wäre es nicht schöner etwas zu haben was funktioniert und verständlich ist?
Lässt sich das etwa nicht machen?
Lässt sich *was* nicht machen? Ich glaube es weiss bisher noch niemand so genau was Du eigentlich willst.

Oft folgen Fragen/Antworten zu regexen einem Muster: Es kommt jemand und fragt wie man aus der "Phantasie"-Zeichenkette 'uhiusxszgx' folgende Informationen bekommt. Darauf bekommt er eine Antwort. Die passt nicht so ganz, also wird nachgebessert. Das passt wieder nicht so ganz, ach und dann müssen noch folgende Zusatzbedingungen gelten...

Das geht dann eine Weile hin und her, endet oft damit das der Fragesteller dann mal sein *richtiges* Problem schildert und prompt eine Lösung bekommt.

Also überspringen wir doch mal das Frage-Antwort-Ping-Pong und Du sagst uns was Du lösen möchtest. Mit echten Zeichenketten und in der Frage bitte auch angeben *warum* du das machst.
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Ich glaube es weiss bisher noch niemand so genau was Du eigentlich willst.
Sorry, ich wollte das Problem ein wenig abstrahieren, um für möglichst wenig Verwirrung zu sorgen (dabei scheine ich das Gegenteil erreicht zu haben).

Ich möchte gerne Daten (Aktienkurse/name) aus einer Html Seite extrahieren. In der .html Datei sind die Daten in einer Tabelle arrangiert. Dabei gibt es zum Teil Informationen, die mich interessieren und Teile, die unwichtig sind. Ich gebe mal ein Beispiel:

Code: Alles auswählen

... restliches html dokument ...
<tr class='kurs'>
<th><div ... ></div></th>
<th colspan='3'><span class='kurs fallend'>Text<a .... return escape("GESUCHTER_STRING1")' class='....></a></span>
</th>
</tr>
<tr class='etwas anderes'>
<th><div ...></div></th>
<th colspan='3'><span class='etwas_anderes'> .... return escape("ANDERER_STRING")' class='...
</th>
</tr>
<tr class='kurs'>
<th><div ... ></div></th>
<th colspan='3'><span class='kurs fallend'>Text<a .... return escape("GESUCHTER_STRING2")' class='....></a></span>
</th>
</tr>
<tr class='kurs'>
<th><div ... ></div></th>
<th colspan='3'><span class='kurs fallend'>Text<a .... return escape("GESUCHTER_STRING3")' class='....></a></span>
</th>
... restliches html dokument ...
Mein Ergebnisstring soll sein:

Code: Alles auswählen

result = ['GESUCHTER_STRING1', 'GESUCHTER_STRING2', 'GESUCHTER_STRING3]
Nach 'ANDERER_STRING' möchte ich dann in einem anderen Durchlauf suchen...

Entschuldigt noch einmal die Verwirrung, für die ich gesorgt habe. Ich dachte, es wäre einfacher den Kern des Problems herauszustellen. Ich sehe nun natürlich ein, dass dabei einige (evt. wichtige) Details verloren gingen...

Vielen Dank,
lunas
BlackJack

Dann würde ich mal BeautifulSoup empfehlen.

Daten aus HTML mittels regulären Ausdrücken zu extrahieren ist kompliziert und fehleranfällig.

Mit BeautifulSoup kannst Du zum Beispiel erst einmal alle `span`-Tags raussuchen, die das gewünschte `class`-Attribut haben und darin dann jeweils das `a`-Tag um die gesuchte Zeichenkette heraus zu holen. Dafür bietet sich dann vielleicht ein regulärer Ausdruck an.
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Hört sich gut an... ich schau's mir mal an.
Daten aus HTML mittels regulären Ausdrücken zu extrahieren ist kompliziert und fehleranfällig.
Oh ja... :roll:

Besten Dank für die Infos.

lunas
Antworten