Seite 1 von 1

re overlapping matches

Verfasst: Sonntag 1. November 2009, 13:35
von glaslos
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?

Verfasst: Sonntag 1. November 2009, 13:48
von karolus
Hallo

Code: Alles auswählen

matches = re.findall("Str?i?|fu|bar", line)
Gruß Karolus

Verfasst: Sonntag 1. November 2009, 13:51
von glaslos
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.

Verfasst: Sonntag 1. November 2009, 13:52
von 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.

Verfasst: Sonntag 1. November 2009, 14:26
von glaslos
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.

Verfasst: Sonntag 1. November 2009, 15:19
von 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).

Verfasst: Sonntag 1. November 2009, 16:03
von glaslos
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.

Verfasst: Sonntag 1. November 2009, 16:10
von 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?

Verfasst: Sonntag 1. November 2009, 16:35
von glaslos
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.