Seite 1 von 1
Aufsplitten vom Text via RegExp statt .split()!
Verfasst: Mittwoch 1. Juli 2009, 18:34
von CiveX
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.
Verfasst: Mittwoch 1. Juli 2009, 18:59
von CODY
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
Verfasst: Mittwoch 1. Juli 2009, 19:07
von CiveX
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.
Verfasst: Mittwoch 1. Juli 2009, 20:07
von CiveX
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:
statt, wie es richtig sein sollte:
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.
Verfasst: Mittwoch 1. Juli 2009, 20:07
von Pekh
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 ...
Verfasst: Mittwoch 1. Juli 2009, 20:09
von CiveX
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.
Verfasst: Mittwoch 1. Juli 2009, 20:23
von jerch
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.)
Verfasst: Mittwoch 1. Juli 2009, 21:44
von CiveX
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...
Verfasst: Mittwoch 1. Juli 2009, 22:08
von jerch
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.
Verfasst: Mittwoch 1. Juli 2009, 22:26
von CiveX
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.
Verfasst: Mittwoch 1. Juli 2009, 22:45
von jerch
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.
Verfasst: Mittwoch 1. Juli 2009, 23:53
von CiveX
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.
Verfasst: Donnerstag 2. Juli 2009, 00:25
von Leonidas
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.
Verfasst: Donnerstag 2. Juli 2009, 00:47
von jerch
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.

Verfasst: Freitag 3. Juli 2009, 14:26
von CiveX
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
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.