Probleme mit regulärem Ausdruck

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
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

Ich brauche dringend eure Hilfe :oops:
Und zwar habe ich Probleme mit den regulären Ausdrücken.

Ich möchte einen regulären Ausdruck erstellen, der bestimmte Präpositionalphrasen findet.
Die Phrasen sollen mit einer bestimmten Präposition („in“, „an“ oder „auf“) beginnen und mit einem Nomen enden.
Mein erster halbwegs brauchbarer Versuch sieht so aus:
r'(in|an|auf)\s([a-zäöü]+[a-zäöüß]+\s[A-ZÄÖÜ][a-zäöüß]{3,})'

Dann bekomme ich aber natürlich nur die Phrasen raus, bei denen nur ein Wort zwischen Präposition und Nomen steht. Also sowas wie „in die Ferne“. Ich möchte aber auch sowas finden wie „in kleinen rot und blau gestrichenen Booten“
Wie schaffe ich es, alle Phrasen zu finden, die meinen Kriterien entsprechen? Hat jemand eine Idee?
problembär

Mein Tip: Frag' mal die Perl-Leute. Die haben auf sowas regelmäßig mehr Bock.

Gruß
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

(in|an|auf)\s #Präposition
([a-zäöüß]{2,}\s)+? #mindestens ein Wort. non-greedy
([A-ZÄÖÜ][a-zäöüß]{3,}) # Nomen
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

defnulls Variante hatte ich auch erst, aber da kommt bei mir "in gestrichenen Booten" raus. Versuch mal das:

Code: Alles auswählen

scan = re.compile(pattern=r'.*\s(in|an|auf)([\sa-zäöüß]*)([A-ZÄÖÜ][a-zäöüß]{3,})').findall

for phrase in scan(r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen'):
    print ''.join(phrase)
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

Danke für die schnellen Antworten!!
pillmuncher hat geschrieben:defnulls Variante hatte ich auch erst, aber da kommt bei mir "in gestrichenen Booten" raus.
Ja, bei mir leider auch.
pillmuncher hat geschrieben: Versuch mal das:

Code: Alles auswählen

scan = re.compile(pattern=r'.*\s(in|an|auf)([\sa-zäöüß]*)([A-ZÄÖÜ][a-zäöüß]{3,})').findall

for phrase in scan(r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen'):
    print ''.join(phrase)
Das funktioniert bei mir teilweise. Also ich bekomme schon mal einige richtige Ausgaben, aber leider auch einige falsche. Z.B. sowas wie:
"an einem
Frühlingsnachmittag" (Warum steht "Frühlingsnachmittag" in einer neuen Zeile?)
oder
"inquisitiven Musterung" (Da müsste ich wohl noch irgendwie festlegen, dass die Präpositionen nicht als Bestandteil anderer Wörter vorkommen.)

Aber das Hauptproblem sind so Ausgaben wie im ersten Beispiel. Sowas kommt relativ häufig vor. Gibts da vielleicht ne ganz einfache Lösung und ich seh sie einfach nicht?
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Warum kommt da 'in gestrichenen Boten' raus? Group(0) (also der gesamte Treffer) liefert doch alles. Na dann eben so:

[\s\.,:]((in|an|auf)\s
([a-zäöüß]{2,}\s)+? #mindestens ein Wort. non-greedy
([A-ZÄÖÜ][a-zäöüß]{3,})) # Nomen
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Defnull:
Du hast recht, ich hatte es nur mit findall() versucht, nicht mit group(0). Old habits die hard...

Gruß,
Mick.
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

Defnull hat geschrieben:Warum kommt da 'in gestrichenen Boten' raus? Group(0) (also der gesamte Treffer) liefert doch alles. Na dann eben so:

[\s\.,:]((in|an|auf)\s
([a-zäöüß]{2,}\s)+? #mindestens ein Wort. non-greedy
([A-ZÄÖÜ][a-zäöüß]{3,})) # Nomen
Da kommt bei mir sowas raus:
'in der Hoffnung', 'in', 'der', 'Hoffnung'

Wo baue ich denn group(0) ein? Wenn ich das versuche, gibt er mir immer nur den ersten Treffer aus, der auf die Kriterien passt.
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Code: Alles auswählen

scan = re.compile(flags=re.VERBOSE, pattern=r"""
    (in|an|auf)\s #Präposition
    ([a-zäöüß]{2,}\s)+? #mindestens ein Wort. non-greedy
    ([A-ZÄÖÜ][a-zäöüß]{3,}) # Nomen
""").search # <- diesmal mit search

phrase = scan(
    r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen'
)

print phrase.group(0)
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

pillmuncher hat geschrieben:

Code: Alles auswählen

scan = re.compile(flags=re.VERBOSE, pattern=r"""
    (in|an|auf)\s #Präposition
    ([a-zäöüß]{2,}\s)+? #mindestens ein Wort. non-greedy
    ([A-ZÄÖÜ][a-zäöüß]{3,}) # Nomen
""").search # <- diesmal mit search

phrase = scan(
    r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen'
)

print phrase.group(0)
Also da gibt er bei mir leider auch wieder nur den ersten Treffer aus dem Korpus aus.

Bisher hat diese Version am besten funktioniert:
pillmuncher hat geschrieben:

Code: Alles auswählen

scan = re.compile(pattern=r'.*\s(in|an|auf)([\sa-zäöüß]*)([A-ZÄÖÜ][a-zäöüß]{3,})').findall

for phrase in scan(r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen'):
    print ''.join(phrase)
Nur die oben beschriebenen falschen Ausgaben bekomme ich nicht weg :?
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Weist du eigentlich, was du da tust oder rätst du nur? Diese Info würde helfen, den Grad des Vorkauens besser an deine Bedürfnisse anzupassen.

Ist nicht böse, aber ernst gemeint. Mit einem Blick in die Doku hättest du re.finditer() und die Beschreibung von re.MatchObject.group() schon längst gefunden.

re.finditer(): Return an iterator yielding MatchObject instances over all non-overlapping matches for the RE pattern in string.

re.MatchObject.group(): Without arguments, group1 defaults to zero (the whole match is returned)
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

So wird ein Schuh draus:

Code: Alles auswählen

scan = re.compile(flags=re.VERBOSE, pattern=r"""
    .*\s(\b(in|an|auf)\b([\sa-zäöüß]*)([A-ZÄÖÜ][a-zäöüß]{3,}))
""").search

def prepphrase(satz):
    phrase = scan(satz)
    if phrase:
        return phrase.group(1)
    else:
        return ""

saetze = [
    r'wir ruderten in kleinen rot und blau gestrichenen Booten und sangen',
    r'wir gingen an einem Frühlingsnachmittag spazieren und redeten',
    r'wir wurden einer inquisitiven Musterung unterzogen',
]

for each in saetze:
    print ">" + prepphrase(each) + "<"
Defnulls regex funktioniert genauso, bloß muss man phrase.group(0) verwenden.

Ich würde das ganze übrigens mit einem DCG-Parser machen, weil regex nicht gerade übersichtlich sind, wie man hieran ja gut erkennen kann.
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

Nein, ich weiß leider nicht was ich tue :roll:

@pillmuncher: Mit deinen Sätzen funktioniert das wunderbar, aber aus meinem Textkorpus gibt er nach wie vor nur den ersten Treffer aus.

Ich werde wohl nochmal ein bisschen rumprobieren :?
Aber danke schonmal für eure Hilfe.
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Was ist es denn eigentlich, was du tun willst? Du bist doch sicherlich nicht eines Morgens aufgewacht und hast gedacht, "hm, heute ist ein schöner Tag um Präpositionalphrasen mit regex zu scannen", oder? Mehr Information von deiner Seite bedeutet bessere Hilfe von unserer.
luna
User
Beiträge: 6
Registriert: Dienstag 13. Oktober 2009, 22:56

Das ist eine alte Aufgabe aus einem "Anfänger Python Kurs". Ich musste die Aufgabe damals nicht abgeben, weil ich durch andere Aufgaben schon genug Punkte gesammelt hatte.
Ich mache die jetzt zur Übung, weil ich besonders mit den regulären Ausdrücken ziemliche Probleme habe.

Die Aufgabe besteht darin, Präpositionalphrasen aus einem Korpus zu extrahieren und sie absteigend nach ihrer Komplexität auszugeben (Kriterien: die Anzahl der Wörter zwischen Präposition und Nomen und die Anzahl der verschiedenen Buchstaben des Nomens).

Und ich habe mich jetzt erstmal an dem regulären Ausdruck versucht, was nicht so richtig erfolgreich war :wink:
Antworten