Home / LinuxUser / 2011 / 09 / Erste Schritte mit Regular Expressions

Newsletter abonnieren

Lies uns auf...

Folge LinuxCommunity auf Twitter

Top-Beiträge

Eingedost
(161 Punkte bei 4 Stimmen)
Aufteiler
(161 Punkte bei 4 Stimmen)

Heftarchiv

LinuxUser Heftarchiv

EasyLinux Heftarchiv

Ubuntu User Heftarchiv

Ubuntu User Heftarchiv

Partner-Links:

Das B2B Portal www.Linx.de informiert über Produkte und Dienstleistungen.

AA_schnipsel-karton_123rf-9152809_maurus.jpg

© maurus, 123rf.com

Schnipseljagd

Erste Schritte mit Regular Expressions

27.08.2011 Computer erleichtern die Arbeit – man muss ihnen nur genau sagen, was sie tun sollen. Mit regulären Ausdrücken beschleunigen Sie das Suchen und Ersetzen von Zeichenketten auf elegante Art.

Neben dem Übertragen und Darstellen von Daten zählt das Suchen und Ersetzen in Textstrukturen und Zeichenketten zu den häufigsten Aktionen beim Umgang mit dem Computer. Bei letzterem helfen die sogenannten regulären Ausdrücke (engl.: "regular expressions"). Deren Konzept umfasst einen komplexen Text- und Zeichenfilter, der ein ein effektives Suchen und Ersetzen in Zeichenketten jeglicher Form ermöglicht – etwa bei Strings in Programmiersprachen, in Ergebnissen von Datenbankabfragen und in Dokumenten als Dateien auf einem Datenträger.

Es spielt dabei keine Rolle, ob die Textdaten strukturiert vorliegen oder nicht – über Erfolg oder Misserfolg entscheidet nur die richtige Formulierung des regulären Ausdrucks (kurz auch Regex oder RE genannt). Allerdings fällt bei strukturierten Dokumentformaten wie CSV, HTML, XML, XSLT und LaTeX der Einsatz der REs meist leichter. Das Regex-Konzept ist weit verbreitet und zeichnet sich durch sehr hohe Stabilität aus. Für die Programmiersprachen Java, Perl, Python, PHP, Ruby, das .NET-Framework und für die Bash gehört es zum Standardumfang.

Die Beschreibung der gesuchten (Zeichen-)Muster folgt bestimmten syntaktischen Regeln, auch Grammatik genannt. Ein Programm wertet diese Grammatik aus und wendet sie auf eine Menge von Zeichen an. Der Rückgabewert umfasst eine Untermenge von Zeichen oder eine Trefferliste. Gibt es keine Übereinstimmung, bleibt diese Liste leer.

Reguläre Ausdrücke formulieren

Bei der Formulierung regulärer Ausdrücke gilt es generell zwei Punkte zu beachten: Erstens hilft es, wenn das Encoding für die Textdaten identisch mit dem des Regex ist. Anderenfalls müssen Sie Umlaute und Sonderzeichen im regulären Ausdruck für das Encoding der Textdaten anpassen. Der zweite Punkt betrifft die Eigenheiten der Regex-Implementierung in der gewählten Programmiersprache: Nicht alle Sprachen unterstützen den POSIX-Standard vollständig und definieren eigene Steuerzeichen.

Grundlagen

Sicherlich haben Sie schon einmal nach einer Person mit einem Namen gesucht, den es in unterschiedlich geschriebenen, aber phonetisch identischen Varianten gibt – etwa nach einem Meier, Schmidt oder Schulze [1]. Die folgenden Beispiele erläutern den Regex-Einsatz anhand dieses Problems. Als Adressbuch dient dabei eine Textdatei, in der Kommas die einzelnen Felder der Einträge trennen (Listing 1). Als Suchwerkzeug für die Kommandozeile kommt grep zum Einsatz.

Listing 1

Fritz Neunmalklug, Am Sterndamm 6, 12401 Berlin, 030 24 58 16
Joachim Mayer, 12 Rue de la Chapelle, CH-1002 Lausanne, 0041 21 67 23 69
Hans Fröhlich, Karlplatz 15, 51111 Köln, 0221 76 34 20
Horst Fischer, Rathausquai 78, 20165 Hamburg, 040 30 19 56 1
Klaus Meier, Mozartweg 7, 01256 Dresden, 0351 58 14 17
Holger maier, Kreuzgasse 15, 86161 Augsburg, 0821 50 23 19

Um Herrn Meier im Adressbuch zu finden, geben Sie Grep zwei Parameter mit: den Namen als Suchmuster und unser Adressbuch als Datei, in der Grep nachsehen soll (Listing 2, Zeile 1). Die Ausgabe umfasst nur eine einzige Zeile (Listing 2, Zeile 2).

Falls Sie sich nicht mehr genau daran erinnern können, ob sich der Gesuchte nun Meier oder Mayer schreibt, erweitern Sie den Grep-Aufruf kurzerhand um den passenden regulären Ausdruck (Listing 2, Zeile 4). Mit der Option -E behandelt Grep das Suchmuster als erweiterten Ausdruck und interpretiert die Steuerzeichen entsprechend. Die Klammern um ei gruppieren die beiden Zeichen e und i, der senkrechte Strich (|) fungiert als Oder-Operator für die beiden Gruppen (ei) und (ay). Die zusätzlichen Klammern um (ei)|(ay) sorgen dafür, dass Grep die beiden Gruppen als kompletten Unterausdruck auswertet.

Listing 2

$ grep Meier adressbuch
Klaus Meier, Mozartweg 7, 01256 Dresden, 0351 58 14 17
$ grep -E "M((ei)|(ay))er" adressbuch
Joachim Mayer, 12 Rue de la Chapelle, CH-1002 Lausanne, 0041 21 67 23 69
Klaus Meier, Mozartweg 7, 01256 Dresden, 0351 58 14 17
$ grep --color -i -E "M.{2}er" adressbuch
Joachim Mayer, 12 Rue de la Chapelle, CH-1002 Lausanne, 0041 21 67 23 69
Klaus Meier, Mozartweg 7, 01256 Dresden, 0351 58 14 17
Holger maier, Kreuzgasse 15, 86161 Augsburg, 0821 50 23 19

Den dritten Eintrag aus dem Adressbuch (Holger maier) unterschlägt Grep bislang, da der Familienname in der Adressdatei fälschlicherweise mit einem Kleinbuchstaben beginnt. Die Option -i ignoriert die Groß- und Kleinschreibung und fördert auch diesen Eintrag zutage.

Da wir aber auch wissen, dass "Meier" aus fünf Buchstaben besteht, vereinfachen wir den Grep-Aufruf so wie in Zeile 8 von Listing 2. Das Muster M.{2}er passt auf alle Zeichenketten, die mit einem M beginnen, gefolgt von zwei beliebigen, alphanumerischen Zeichen (.{2}) und mit der Buchstabenfolge er am Ende. Welche besonderen Zeichen in einem Muster welche Bedeutung haben, zeigt die Tabelle "Besondere Zeichen in regulären Ausdrücken".

Die Grep-Option --color erweist sich im Alltag als sehr nützlich: Sie hebt diejenigen Zeichen im Suchergebnis hervor, auf die das angegebene Muster passt (Abbildung 1) – in unserem Fall also die passenden Familiennamen.

Abbildung 1

Abbildung 1: Grep mit farbiger Hervorhebung des Suchergebnisses.

Besondere Zeichen in regulären Ausdrücken

Zeichen Bedeutung Beispiel Treffer bei
? vorhergehendes Element ist null oder ein Mal vorhanden (20)?11 2011, 11
+ mindestens eine Wiederholung des vorhergehenden Elements ab+ ab, abb, abbb, …
* keine, eine oder mehrere Wiederholungen des vorhergehenden Elements ab* a, ab, abb, abbb, …
| logisches Oder a|b a, b
. beliebiges einzelnes Zeichen Betr.g Betrag, Betrug, …
^ am Zeilenanfang ^Berlin Zeile beginnt mit Berlin
$ Zeilenende Berlin$ Zeile endet auf Berlin
[...] Bereich [a-fA-F] Zeichen a bis f und A bis F
[^...] Ausschlussbereich [^a-f] alle Zeichen außer a bis f
(...) gruppiert Elemente Loch(streifen|karte) Lochstreifen, Lochkarte
{x,y} Menge {Minimum, Maximum} \w{3,8} mindestens drei und maximal acht alphanumerische Zeichen
\w alphanumerische Zeichen (a-z, A-Z, 0-9 und _) \w+; \w+ zwei Worte, durch Semikolon und ein Leerzeichen voneinander getrennt
\s Leerzeichen (identisch zu \t\n\r\f) \w+\s+\w+ zwei Worte, durch mindestens ein Leerzeichen oder einen Tabulator getrennt
\d Ziffern (Grep: [0-9]) Zeile \d Zeile 0 bis Zeile 9
Um eines der besonderen Zeichen zu finden, müssen Sie es mittels Backslash escapen. Mit \. finden Sie beispielsweise einen Punkt.

Schlangenbeschwörung

Die Programmiersprache Python macht es Ihnen an vielen Stellen sehr leicht. Möchten Sie alle Varianten von Meier aus einer Namensliste herausfischen, dann kodieren Sie das wie in Listing 3 gezeigt. In Zeile 6 wird jeder Eintrag der Namensliste mit den möglichen Varianten verglichen und als Ergebnis lediglich Meier ausgegeben. Zu mayer gibt es keine exakte Entsprechung in der Variantenliste, weswegen Python diesen Eintrag nicht findet.

Listing 3

# -*- coding: utf-8 -*-
namensliste = ["Meier", "Müller", "Schulze", "mayer"]
variantenliste = ["Meier", "Meyer", "Maier", "Mayer"]
for eintrag in namensliste:
        if eintrag in variantenliste:
                print(eintrag)

Komfortabler funktioniert das Ganze mithilfe von Funktionen für Reguläre Ausdrücke. Diese stellt Python über das Modul re ([2],[3]) bereit – das Kürzel steht für "regular expressions". Dieses Modul wird in Listing 4 in der dritten Zeile deklariert, ab diesem Punkt lassen sich die Funktionen aus re im Skript nutzen. In Zeile 5 bereitet die Funktion re.compile() das Muster zunächst vor. Dabei steht im Muster [ae] für eines der Zeichen a und e, sinngemäß dasselbe gilt für [iy]. Das Caret (^) benennt den Wortanfang, das Dollarzeichen ($) das Wortende.

Listing 4

# -*- coding: utf-8 -*-
import re
namensliste = ["Meier", "Müller", "Schulze", "mayer"]
muster = re.compile('^m[ae][iy]er$', re.IGNORECASE)
for eintrag in namensliste:
        if muster.match(eintrag):
                print(eintrag)

Beim zweiten Parameter des Funktionsaufrufs handelt es sich um re.IGNORECASE, eine vordefinierte Konstante aus dem re-Modul. Sie bewirkt, dass beim Vergleich des Musters die Groß- und Kleinschreibung keine Rolle spielt. Die Funktion re.match() nimmt den Vergleich des Musters mit der Zeichenkette vor. Auf die Namensliste angewendet, erhalten Sie bei der Ausgabe in Zeile 8 sowohl Meier als auch mayer. Diese Variante deckt also alle acht möglichen Schreibweisen ab, ohne sie dazu wie in Listing 3 explizit aufzählen zu müssen.

Tip a friend    Druckansicht Bookmark and Share
Kommentare

2936 Hits
Wertung: 92 Punkte (3 Stimmen)

Schlecht Gut

Infos zur Publikation

Infos zur Publikation

LinuxUser 05/2014

Aktuelle Ausgabe kaufen:

Heft als PDF kaufen

LinuxUser erscheint monatlich und kostet in der Nomedia-Ausgabe EUR 5,95 und mit DVD EUR 8,50. Weitere Informationen zum Heft finden Sie auf der LinuxUser-Homepage.

Im LinuxUser-Probeabo erhalten Sie drei Ausgaben für 3 Euro. Das Jahresabo (ab EUR 60,60) können Sie im Medialinx-Shop bestellen.

Tipp der Woche

Bilder vergleichen mit diffimg
Bilder vergleichen mit diffimg
Tim Schürmann, 01.04.2014 12:40, 1 Kommentare

Das kleine Werkzeug diffimg kann zwei (scheinbar) identische Bilder miteinander vergleichen und die Unterschiede optisch hervorheben. Damit lassen sich nicht nur Rätsel a la „Orignial und Fäls...

Aktuelle Fragen

programm suche
Hans-Joachim Köpke, 13.04.2014 10:43, 8 Antworten
suche noch programme die zu windows gibt, die auch unter linux laufen bzw sich ähneln sozusagen a...
Funknetz (Web-Stick)
Hans-Joachim Köpke, 04.04.2014 07:31, 2 Antworten
Bei Windows7 brauche ich den Stick nur ins USB-Fach schieben dann erkennt Windows7 Automatisch, a...
Ubuntu 13.10 überschreibt immer Windows 8 Bootmanager
Thomas Weiss, 15.03.2014 19:20, 8 Antworten
Hallo Leute, ich hoffe das ich richtig bin. Ich habe einen Dell Insipron 660 Ich möchte gerne Ub...
USB-PTP-Class Kamera wird nicht erkannt (Windows-only)
Wimpy *, 14.03.2014 13:04, 15 Antworten
ich habe meiner Frau eine Digitalkamera, AGFA Optima 103, gekauft und wir sind sehr zufrieden dam...
Treiber
Michael Kristahn, 12.03.2014 08:28, 5 Antworten
Habe mir ein Scanner gebraucht gekauft von Canon CanoScan LiDE 70 kein Treiber wie bekomme ich de...