Aufsplitten vom Text via RegExp statt .split()!

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
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Howdy,
und wieder ich!

Immer noch am Thema reguläre Ausdrücke.

Ich muss einen Text tokensieren (und normalisieren), und dann je Zeile 1 Token ausgeben. Tokensieren heißt jedes Wort/Satzzeichen entnehmen und ausgeben oder in Liste einfügen.

Folgender Beispieltext untokensiert:
Soddoma (eigentlich Giovannantonio Bazzi), tpital. Maler,
geb. 1477 zu Vercelli in Savoyen, bildete sich seit 1498 nach
Leonardo da Vinci in Mailand und kam 1501 nach Siena, wo er
verschiedene Fresken und Tafelbilder ausführte;
tokensiert und bearbeitet ausgegeben sieht der Text dann so aus: http://pastebay.com/26238 !

Ich habe aber absolut keinen Plan wie ich vorgehen soll. Ich stehe wirklich total auf dem Schlauch.

Hat jemand eine Ahnung wie ich vom Beispieltext zum bearbeitetem Text komme via reg. Ausdrücken?

Ich bekomm das so falsch und krumm raus, bei der meine Ausgabe dann so aussieht: http://pastebay.com/26242 ! Das ist aber natürlich total falsch, da ich ja zuerst Satzzeichen ausgebe, und dann Wörter.
Benutzeravatar
CODY
User
Beiträge: 3
Registriert: Mittwoch 1. Juli 2009, 18:43

Hey, CiveX!

Wie wär's zum splitten mit:

Code: Alles auswählen

zeichen = re.compile(r'([^a-zäöüA-ZÄÖÜ0-9ß\s+])')
text = re.split(zeichen, text)
Allerdings taucht zwischendurch immer wieder eine Leerzeile bzw. Whitespace auf, die/das ich nicht wirklich zuordnen kann.

Original:
Soddoma (eigentlich Giovannantonio Bazzi), ital. Maler,
geb. 1477 zu Vercelli in Savoyen, bildete sich seit 1498 nach
Ausgabe:
Soddoma
(
eigentlich Giovannantonio Bazzi
)

,
ital
.
Maler
,

geb
.
1477 zu Vercelli in Savoyen
,
bildete sich seit 1498 nach
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Okay, das ist mir neu mit re.split, das kannte ich noch nicht.

So könnte das gehen, allerdings kann ich nicht wirklich mit split arbeiten, weil ich noch "normalisieren" muss dazwischen, und zwar nach Kriterium:
o Wörter, die normalerweise kleingeschrieben werden und nur am Satzanfang mit großem Anfangsbuchstaben vorkommen,
sollen nun auch am Satzanfang mit einem Kleinbuchstaben beginnen.
o Wörter, die auch im Satzinneren großgeschrieben werden (z.B. Nomina), sollen dagegen nicht verändert werden.
Das heißt, es muss zwangsläufig irgendwie irgendwo mit einer for-schleife gearbeitet werden, die dann jedes wort/zeichen durchgeht..

Also wird .split alleine nicht laufen :(!

Aber super, danke schonmal! Was neues gelernt!

PS: Bevor sich hier welche Wundern. Ja, das ist Linguistik. Nein, das sind keine Hausaufgaben. Ich muss den Stoff halt nacharbeiten, da ich ein paar Sachen verpasst habe.
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Okay, ich habs:

Code: Alles auswählen

# reg. Ausdruck für sehr grobe Tokensierung
token_grob_re = re.compile(ur'[,;)(.:!?]|[a-zäöüA-ZÄÖÜ]+|[0-9]+')

# grobe Tokensierung matchen
tokens = token_grob_re.findall(text)
Soweit, so gut!

Problem ist allerdings, dieser RegExp macht aus:

Code: Alles auswählen

ital
.
Maler
,
geb
.
1477
statt, wie es richtig sein sollte:

Code: Alles auswählen

ital.
Maler
,
geb.
1477
Es erkennt also Abkürzungen nicht. Ist auch nicht definiert, und ich weiß nicht wirklich wie ich es definieren soll.

Abkürzungen alla geb. ital. bzw. aber auch p.s. ü.ä. Dr. PhD. etc. sollen erkannt werden.
Zuletzt geändert von CiveX am Mittwoch 1. Juli 2009, 20:13, insgesamt 3-mal geändert.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Ich an deiner Stelle würde ja mal mit .split in der Shell experimentieren. Dein Problem ist nämlich keines. Und .split ist genau das, was du suchst ...
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Mit .split() wäre das ganze schon längst erledigt.

Es geht hier darum die reg. Ausdrucke kennenzulernen, deshalb soll in diesem Teil die RegExp das .split() ersetzen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Versuchs mal damit:

Code: Alles auswählen

reg_ex = re.compile(r'\s+|([^\wäüöÄÖÜß])')
token_list = list(i for i in re.split(reg_ex, s) if i)
In der RegEx müßtest Du ggf. weitere "Nicht-Split"-Zeichen ergänzen. Evtl. kontextabhängige Spezialbehandlungen einzelner Zeichen müßtest Du gesondert behandeln, da wirds mit RegEx schwierig bis unmöglich. (Tipp: alle zu bedenkenden Ausnahmen definieren und gesondert prüfen oder in die obige RegEx mit ODER einfügen.)
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Jo, haste recht Jerch. Das Problem ist ein sehr schwieriges. Das lasse ich mal links liegen vorerst, und kümmere mich darum:
o Wörter, die normalerweise kleingeschrieben werden und nur am Satzanfang mit großem Anfangsbuchstaben vorkommen,
sollen nun auch am Satzanfang mit einem Kleinbuchstaben beginnen.
o Wörter, die auch im Satzinneren großgeschrieben werden (z.B. Nomina), sollen dagegen nicht verändert werden.
Wie gehe ich da nu vor?

Mit

Code: Alles auswählen

# reg. Ausdruck für sehr grobe Tokensierung
token_grob_re = re.compile(ur'[,;)(.:!?]|[a-zäöüA-ZÄÖÜ]+|[0-9]+')

# grobe Tokensierung matchen
tokens = token_grob_re.findall(text)
splitte ich ja den gesamten Text in einzelne Token auf...
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Also mit das ist nun definitiv nicht einfacher als das vorherige Problem. Um alle Substantive zu finden, mußt Du ja schlimmstenfalls die Funktion eines Tokens im Satz erkennen, viel Spaß mit einem fuzzy-Parser. Wenn Dir das in Python halbwegs elegant gelingt, ist Dir wahrscheinlich ein Job bei Google sicher. ;)

Ich frage mich, was Du da nacharbeiten willst, theoretisch sollte Dir doch die Größe dieses Problemes bewußt sein. Bzw. kannst Du für solche komplexen Fragestellungen hier keine Lösung erwarten, da keiner eben mal so einen Parser aus dem Ärmel schüttelt.
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Ich erwarte doch gar nix. Ich bin schon für Denkanstöße und Hinweise in die richtige Richtung schon sehr dankbar.

Nacharbeiten muss ich den Stoff, denn ich verpasst habe. Und das sind nunmal alte Aufgaben aus der Linguistik.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Hab Ihr da nicht mehr gegeben? Sollst Du die Fragestellungen wirklich in Code beantworten? Ich bin mir nicht sicher, ob Du mit der Sache in einem Programmierforum richtig bist, da die Mechanismen von formalen Sprachen sich nur bedingt auf natürliche Sprachen anwenden lassen. Für linguistische Tricks ist das Pythonforum nicht der beste Anlaufpunkt.

Für formale Sprachen hingegen kann Dir hier bestimmt geholfen werden.
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Na sicher ist das Forum das richtige :).

Es ging ja darum, wie man mit RegExp die eigentliche split() ersetzt. Das ist ja längst beantwortet :).

Ob das jetzt Linguistik ist, oder mathematik, im Endeffekt geht's um den Code.

Hier wird ja nicht linguistisches gefragt, bis auf die Nomina, die wiederum ist aber auch nur als Beispiel gedacht.

Ob ich jetzt mit Python einen Text abfrage oder eine Datenbank Texteinträgen ist im Endeffekt egal.

Die Frage hätte genausogut lauten können: Datenbankeinträge die in der Datenbankspalte XYZ großgeschrieben werden sollen nicht verändert werden.

Ich werfe die Frage meist einfach in den Raum, eventuell gibt es hier den einen oder anderen der damit knobbeln will, und mir dann eventuell Anstöße gibt. Falls nicht, auch nicht schlimm.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

CiveX hat geschrieben:Ob das jetzt Linguistik ist, oder mathematik, im Endeffekt geht's um den Code.
Es geht schon immer um den Code, aber bei Mathematik kann man "komische" Daten schlichtweg ablehnen ("kann nicht vorkommen; ist nicht definiert"), die Linguistik besteht aber nur aus solchen Daten.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Also jetzt verwirrst Du mich. Du bist doch nicht ernsthaft der Auffassung, daß ein Nachschlagen im Wörterbuch (z.B. DB) vergleichbar ist mit Deiner Nomina-Aufgabenstellung bezogen auf natürliche Sprachen?

Womöglich habe ich Dich gänzlich mißverstanden mit Deinem Anliegen und daher eher in Richtung Linguistik zu diskutieren versucht.

Ich habe Dein Nomina-Problem als Codeanfrage verstanden und entsprechend darauf geantwortet. Natürlich gibt es Möglichkeiten, sich dem Problem mit "workarounds" (z.B. gut gefüllten Wörterbüchern) anzunähern, da den natürlichen Sprachen aber der mathematische Formalismus fehlt, bleiben diese Versuche allesamt Krücken und gerade das ist doch Gegenstand der Linguistik (u.a.). Daher mein Hinweis in diese Richtung, Du kannst von formal denkenden Menschen wie Programmierern (man möge es mir verzeihen) hier wahrscheinlich keine große Hilfe erwarten. (Es sei denn, ein Herr Chomsky2 weilt unter uns.)

Oder aber Du solltest die Aufgabenstellung präzisieren mit weiteren Vorgaben etc., damit unser Formalismus einen Ansatzpunkt hat. Mit
o Wörter, die normalerweise kleingeschrieben werden und nur am Satzanfang mit großem Anfangsbuchstaben vorkommen,
sollen nun auch am Satzanfang mit einem Kleinbuchstaben beginnen.
o Wörter, die auch im Satzinneren großgeschrieben werden (z.B. Nomina), sollen dagegen nicht verändert werden.


Wie gehe ich da nu vor?
ist uns da nicht geholfen.

BTW: Formalismus war in den 50igern im Ostblock ein schwerer Vorwurf, der, gegen einen Funktionär ausgesprochen, dessen politisches Ende bedeutete. :lol:
CiveX
User
Beiträge: 34
Registriert: Samstag 23. Mai 2009, 11:48

Hali, Halo, und weiter gehts:

Code: Alles auswählen

# Alle Wörter am Satzanfang finden
for match in re.finditer(r'.\s+([A-Z][a-z]*)\s+',text):
    wort = match.group(1)
    print "Altes Wort:", wort
    # Ist das gefundende Wort woanders im Text kleingeschrieben
    if wort.lower() in  tokens_lowercase_set:
        # Dann wird das Wort am Satzanfang kleingeschrieben
        wort = wort.lower()
    print "Neues Wort:", wort
Im tokens_lowercase_set sind alle Wörter aus dem Text, die klein geschrieben sind.

Mein Problem ist nun, ganz am ende wort = wort.lower() macht er genau das, was ich will.

Wie gehe ich ab da vor, dass er mir das neue Wort im text ersetzt? Ich scheitere hier mit sub().


Also z.B. die Funktion guckt sich den Text an und findet am Satzanfang "Problematisch" und irgendwo "problematisch".

Mittels

Code: Alles auswählen

re.finditer(r'.\s+([A-Z][a-z]*)\s+',text)
wird "Problematisch" gefunden. Und "problematisch" wird in tokens_lowercase_set aufgenommen mit einer anderer Funktion:

Code: Alles auswählen

token_lowercase_re = re.compile(ur'\s+([a-zäöüß]+)')
lowercase_tokens = token_lowercase_re.findall(text)
tokens_lowercase_set = set([])
for lowercase_token in lowercase_tokens:
    tokens_lowercase_set.add(lowercase_token)
Nach meiner Funktion vergleicht er beides und macht aus dem vom Satzanfang "Problematisch" ein "problematisch". Da hört's dann auf.

Ich möchte nun aber das gefundene "Problematisch" im Text mit "problematisch" ersetzen. Also das veränderte "problematisch" wieder in text zurüklegen.

Ich weiß, dass es mit sub() gehen soll, ich scheitere aber an der Implentation.
Antworten