re overlapping matches

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
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Folgendes Problem:

Ich möchte in einem String:

Code: Alles auswählen

"Das ist ein String"
Nach Pattern:

Code: Alles auswählen

"St|Str|Stri|fu|bar"
suchen. re.findall() gibt mir:

Code: Alles auswählen

import re

line = "Das ist ein String"
matches = re.findall("St|Str|Stri|fu|bar", line)
print matches

Code: Alles auswählen

matches = ['St']
Ich hätte jedoch in diesem Fall gerne:

Code: Alles auswählen

matches = ['Stri']
Ich habe zwei Möglichkeiten gefunden das Problem zu lösen:

Ich schaue ob sich Elemente des Patterns im Pattern wiederholen und sortiere das Pattern entsprechend:
Aus:

Code: Alles auswählen

"St|Str|Stri|fu|bar"
Wird:

Code: Alles auswählen

"Stri|Str|St|fu|bar"
Oder:
Ich entferne Treffer aus dem Pattern und schaue ob es weitere Treffer gibt. Anschließend vergleiche ich die gefundenen Treffer und nehme mir den "längsten".

Ich finde beide Lösungen nicht besonders elegant. Leider hat re.findall() kein overlapping=True flag.

Hat jemand von euch eine gute/elegante Idee wie ich das Problem umschiffen kann?
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

Code: Alles auswählen

matches = re.findall("Str?i?|fu|bar", line)
Gruß Karolus
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

karolus hat geschrieben:Hallo

Code: Alles auswählen

matches = re.findall("Str?i?|fu|bar", line)
Gruß Karolus
Verzeihung, ich habe noch eine Kleinigkeit vergessen :) Ich habe keinen Einfluss auf den Inhalt des Patterns. Ich könnte deine Lösung höchstens nachträglich anwenden.
lunar

Der Sinn ist mir nicht ganz klar, wozu brauchst Du hier reguläre Ausdrücke?

Code: Alles auswählen

patterns = sorted("St|Str|Stri|fu|bar".split('|'), key=len)
for pattern in patterns:
    if pattern in line:
        break
print(pattern)
Wenn Du den längsten Treffer einer Liste regulärer Ausdrücke möchtest, dann musst Du statt "in" eben Funktionen aus "re" nehmen und die Länge der gefundenen Zeichenkette prüfen.
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

lunar hat geschrieben:Der Sinn ist mir nicht ganz klar, wozu brauchst Du hier reguläre Ausdrücke?

Code: Alles auswählen

patterns = sorted("St|Str|Stri|fu|bar".split('|'), key=len)
for pattern in patterns:
    if pattern in line:
        break
print(pattern)
Wenn Du den längsten Treffer einer Liste regulärer Ausdrücke möchtest, dann musst Du statt "in" eben Funktionen aus "re" nehmen und die Länge der gefundenen Zeichenkette prüfen.
Danke lunar, dein Tipp hat das Problem gelößt. Ich verwende nun:

Code: Alles auswählen

patterns = sorted(patterns, key=len, reverse=True)
re benötige ich, da das Pattern nicht so einfach ist wie im Beispiel. Ich dachte ich halte es möglichst einfach um das Problem klar zu skizzieren.
lunar

Bei regulären Ausdrücken bringt das nichts. Die Länge eines Musters sagt nichts aus über die Länge der passenden Zeichenkette (vgl. '.*' vs. 'foobar'). Du musst jedes Muster prüfen, und dann die Liste mit gefundenen Zeichenketten sortieren (bzw. die Länge der gefundenen Zeichenketten prüfen).
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

lunar hat geschrieben:Bei regulären Ausdrücken bringt das nichts. Die Länge eines Musters sagt nichts aus über die Länge der passenden Zeichenkette (vgl. '.*' vs. 'foobar'). Du musst jedes Muster prüfen, und dann die Liste mit gefundenen Zeichenketten sortieren (bzw. die Länge der gefundenen Zeichenketten prüfen).
Vielen Dank für den Einwand, aber in meinem Fall funktioniert es, da sich meine Ausdrücke um die Länge eines bestimmten Strings unterscheiden, das Sortieren vor dem Zusammenfügen und re.compile also das gewünschten Ergebnis liefert.
lunar

Besonders robust ist das allerdings nicht. Spricht denn etwas dagegen, einfach alle Ausdrücke zu probieren und dann den längsten Treffer auszuwählen?
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

lunar hat geschrieben:Besonders robust ist das allerdings nicht. Spricht denn etwas dagegen, einfach alle Ausdrücke zu probieren und dann den längsten Treffer auszuwählen?
Habe ich auch schon überlegt, aber es kann mehrere gültige Treffer geben. Also, ich suche nach foo, foobar und bar. Wenn foobar da ist möchte ich foo nicht, aber bar möchte ich trotzdem.
Antworten