Übung Korpuslinguistik: Regular Expressions

Regular Expressions für die Korpuslingustik

Hinter den "Regular Expressions" (Reguläre Ausdrücke) verbirgt sich eine mächtige Sprache, um bestimmte Such- und Ersetzungsmuster zu definieren. Man kann damit z.B. aus einer Textdatei alle URLs (Adressen) von Webseiten extrahieren, ohne genau zu wissen, was für Adressen da stehen werden. Oder man kann nach Wörtern suchen, die mit einem Grossbuchstaben beginnen und mit -en enden. Oder man kann aus einem Text eine Wortliste erstellen, wo jedes Wort und jedes Satzzeichen auf einer eigenen Zeile steht.

Hier werden nur ganz grundlegende Regeln der Regular Expressions gezeigt, sowie einige Muster, die für typische korpuslinguistische Bedürfnisse gebraucht werden. Eine Einführung bietet aber z.B. die Seite www.regular-expressions.info, die Unixfibel, der Wikipedia-Eintrag, sowie viele andere Quellen, z.B. auch die Online-Hilfe des Texteditors BBEdit für Mac OS X. BBEdit bietet sich beispielsweise an, um mit regulären Ausdrücken zu arbeiten. Im normalen "Find & Replace"-Funktion kann man damit arbeiten, wenn man das Häkchen "Use Grep" setzt ("grep" war eines der ersten Programme, das mit regulären Ausdrücken umgehen konnte; der Name wird deshalb oft synonym mit den regular expressions verwendet).

In einem Kapitel zum Import von Korpora in die Datenbank Filemaker wird an einem Beispiel gezeigt, wie mit regulären Ausdrücken eine kommaseparierte Textdatei erstellt werden kann.

Grundlagen

Grundsätzlich bedeuten im Suchmuster die Buchstaben sich selbst. Das Suchmuster
Hund
findet also alle Vorkommen von "Hund". Weiter können z.B. folgende Zeichen verwendet werden:

.Der Punkt steht für ein x-beliebiges Zeichen.
*
Der Stern bedeutet, dass das Zeichen vor dem Stern 0 bis unendlich mal hintereinander stehen darf.
+
Das Zeichen vor dem Plus muss mind. 1 mal bis unendlich mal hintereinander da sein.
?
Das Zeichen vor dem Fragezeichen kann 1 mal oder gar nicht vorkommen.

Beispiele:
Hund.*
findet: Hund, Hunde, Hundes, Hundeschnauze, Hundeball etc.

H.nd
findet: Hund, Hand, Hind, Hond, Hend

Hund.+
findet: Hunde, Hundes, Hundeschnauze etc., aber nicht Hund

Hund.?
findet: Hund, Hunde, aber nicht Hundeschnauze, Hundes etc.

Oder ein etwas komplizierteres Beispiel:

http:\/\/(www\.)?.+?\.com

Dieses Suchmuster findet Internetadressen der Art http://www.irgendwas.com. Das "www" muss nicht stehen, kann aber. Und wir suchen nur nach Endungen mit .com. Folgende Besonderheiten sind ersichtlich:

Spezielle Zeichen

[aeiou]
Klassen: Was in eckigen Klammern steht, definiert eine Klasse an Zeichen. Im Beispiel findet die Klammer einen Buchstaben, der entweder a, e, i, o oder u ist. Man kann die Klassen auch so angeben:
[a-zA-Z]

Damit wird ein Buchstabe, gross oder klein, von a-z gefunden. Das folgende Suchmuster

Renntier[es]

findet also "Renntiere" oder "Renntiers". Stünde hinter der Klammer noch ein Fragezeichen, würde auch "Renntier" gefunden.

\r \n
Zeilenschaltung, einmal normal und einmal im Unix-Stil. Ist man nicht sicher, welche Art der Zeilenschaltung im Dokument vorhanden sind, macht man einfach eine Klasse daraus: [\r\n]
\t
Tabulator
\s
Jede Art von Leerzeichen: Leerzeichen, Zeilenschaltung, Tabulator, Seitenwechsel
\S
Jede Art von Nicht-Leerzeichen: Jeder Buchstabe ausser jene Zeichen, die mit \s gefunden werden.
\w
Jeder Wort-Buchstabe (also a-z, A-Z, 0-9, _ und wenige mehr).
\W
Jeder Nicht-Wort-Buchstabe (Gegenteil von \w).
\d
Zahlen 0-9.
Möchte man also z.B. vierstellige Jahreszahlen finden, schreibt man einfach:
\d\d\d\d

Möchte man hingegen Zahlen beliebiger Länge finden, schreibt man:

\d+
\D
Alle Nicht-Zahlen (inkl. Zeilenschaltung)

Suchen und ersetzen

Auf alles, was in normale Klammern gesetzt wird, kann nach der Suche zurückgegriffen werden. Ein Beispiel: Ich habe einen Text, in dem Datumsangaben der Art "2005-10-1" vorkommen. Ich möchte aber diese so formatiert haben: "01. 10. 2005". Dann formuliere ich zuerst ein Suchmuster, das Daten der ersten Art findet:
\d\d\d\d-\d+-\d+

Damit finde ich zuverlässig diese Datumsangaben, egal ob die Zahlen für Monat und Tag ein- oder zweistellig sind. Jetzt muss ich ja aber das Gefundene umformen. Dazu setze ich erstmal Klammern um das Suchmuster, denn alles was in Klammern steht, wird im Speicher behalten:

(\d\d\d\d)-(\d+)-(\d+)

Mich interessieren nur die Zahlen, die Bindestriche dazwischen können wir gleich wieder vergessen. Der Clou ist jetzt, dass ich als Ersetzung mit \1, \2, \3 etc. auf den Inhalt der Klammern zurückgreifen kann. \1 ist der Inhalt der ersten, \2 der zweiten Klammer etc. Als Ersetzungsmuster schreibe ich also:

\3\. \2\. \1

Damit wird das Datum jeweils umformatiert. Beachte: Der Punkt wird hier wieder mit einem umgekehrten Schrägstrich maskiert, damit klar ist, dass es sich beim Punkt nicht um den Punkt handelt, der für ein beliebiges Zeichen steht, sondern tatsächlich um einen Punkt.

Mit dieser Methode kann man ganz schnell einen Text, der irgendwie falsch formatiert ist, umformatieren. Z.B. wenn ich eine Wortliste haben, wo immer hinter dem Wort eine Zahl steht, z.B. die Frequenz, mit der das Wort auftaucht, und ich aus irgendwelchen Gründen die Zahl aber vor dem Wort stehen haben möchte, dann kann ich das mit einer solchen Suchen-und-Ersetzen-Aktion schnell erledigen.

Nützliche Muster für die Korpuslinguistik

Wortlisten erstellen

Um aus normalem Text Wortlisten zu erstellen, bei denen pro Zeile nur ein Wort oder Satzzeichen steht, kann man mit regulären Ausdrücken so vorgehen: Zuerst ersetzen wir alle Arten von Leerzeichen (egal, wie oft sie hintereinander vorkommen) durch Zeilenschaltungen:
Suche nach:     \s+
Ersetzen durch: \r

Dann trennen wir alle Arten von Interpunktion durch Zeilenschaltungen. Gewisse Versionen von regulären Ausdrücken verstehen das Suchmuster [:punct:] um alle Interpunktionszeichen zu finden. Jene, die in BBEdit implementiert ist, leider nicht. Dann muss man halt eine Klasse von Interpunktionszeichen erstellen (und dabei das Maskieren der wörtlich zu verstehenden Zeichen nicht vergessen!):

Suche nach:     ([\.,:;!\?"'\(\)\[\]\-/])
Ersetzen durch: \r\1\r

Zu beachten: Die Klasse ist definiert durch die eckigen Klammern, zusätzlich werden normale Klammern verwendet, mit denen der tatsächlich gefundene Inhalt gemerkt wird, damit mit \1 beim Ersetzen wieder darauf zurückgegriffen werden kann.

Jetzt ist es noch so, dass teilweise zwei Zeilenschaltungen hintereinander vorkommen (nach Interpunktionszeichen). Diese können wir so eliminieren:

Suche nach:     \r+
Ersetzen durch: \r

Fertig ist die Wortliste!