Die regulären Ausdrücke (ITG/slu)

1. Einführung

Das Konzept der regulären Ausdrücke (abgekürzt „RA“ oder „RE“ für engl. Regular Expressions) ist ein System zur variablen bzw. vereinfachten Beschreibung von Zeichenketten („strings“). Sie werden praktisch ausschließlich zum Auffinden von Zeichenketten in Textdokumenten verwendet. Als ihr „Erfinder“ gilt der amerikanische Mathematiker Stephen Cole Kleene (1909-1994). Ursprünglich aus dem Bereich der Informatik bzw. der Programmierung stammend, sind die regulären Ausdrücke auch im Umfeld der Korpuslinguistik von großem Nutzen.

Ein kleines Beispiel kann Funktionsweise und Vorteile ihres Einsatzes illustrieren. Angenommen, man möchte in einem Text die beiden Wörter „Band“ und „Bund“ finden. Ohne die Verwendung von regulären Ausdrücken müsste man, nach einander, zunächst nach dem Wort „Band“ und anschließend nach dem Wort „Bund“ suchen:

Finde "Band" in Text
Finde "Bund" in Text

Beim Einsatz regulärer Ausdrücke wäre diese Aufgabe mit einer einzigen Suchaktion zu erledigen, nämlich folgendermaßen:

Finde "B[au]nd" in Text

Die eckigen Klammern bezeichnen eine sogenannte Zeichenklasse, die in der Weise zu interpretieren ist, dass innerhalb der Klammern aufgeführten Zeichen als Alternativen zu verstehen sind. Im gegebenen Beispiel wäre also paraphrasiert zu lesen: Find ein großes B, gefolgt von entweder einem a oder einem u, gefolgt von einem n, gefolgt von einem d.

Das Konzept der Regulären Ausdrücke ist in einer Vielzahl von Softwareprodukten  implementiert (u. a. in den meisten Editoren, außerdem auch im Datenbankmanagementsystem MySQL). Nicht selten gibt es dabei anwendungsspezifische Besonderheiten und Erweiterungen des Basiskonzepts der Regulären Ausdrücke.

2. Literale und Metazeichen

Das Konzept der REs unterscheidet zwischen Literalen und Metazeichen. Literale stehen jeweils für sich selbst, Metazeichen haben Sonderbedeutung. Die wichtigsten Metazeichen lauten wie folgt:

Metazeichen Kategorie Bedeutung
. (Punkt) Platzhalter ein beliebiges Zeichen
[abcDE396;:] Zeichenklasse Zeichengruppe (jeweils genau ein Zeichen aus der angegebenen Liste, also: entweder a oder b oder c oder D …).
[a-z] Zeichenklasse Ein beliebiges Zeichen aus dem Bereich zwischen a und z. Grundlage ist die Anordnung der Zeichen in der ASCII-Tabelle. Zeichenbereiche bei denen der ASCII-Wert des erstgenannten Zeichens größer ist als der des folgenden, sind ungültig. Nicht ASCII-kodierte Buchstaben sind nicht enthalten (z. B. deutsche Umlaute oder ß)
[a-zäöüß] Zeichenklasse Ein beliebiger ASCII-kodierter Kleinbuchstabe inklusive der genannten deutschen Sonderzeichen
[^0-9] Zeichenklasse Das ^ („Dach“) innerhalb einer Zeichenklassendefinition bezeichnet eine Negation. Hier im Beispiel: keine Ziffer
[%-.] Zeichenklasse Matcht alle Zeichen, deren ASCII-Werte zwischen x25 (%) und x2E (.) liegen, nämlich: %,&'()*+´-. (s. ASCII-Tabelle)
[^\t-~] Zeichenklasse Alle *nicht*-ASCII-Zeichen
\d Zeichenklasse beliebige Ziffer (= [0-9])
\s Zeichenklasse beliebiger Whitespace-Character (Leerzeichen oder Tabstopp; = [ \t])
\w Zeichenklasse beliebiges alphanumerisches Zeichen (Buchstabe oder Zahl; keine Satzzeichen, Leerzeichen etc.; auch keine nicht-ASCII Sonderzeichen wie z. B. deutsche Umlaute oder ß)
\D Zeichenklasse Beliebiges Zeichen außer Ziffern. Generell steht die Großschreibung des entsprechendes Buchstabens jeweils für die Negation der mit dem Kleinbuchstaben markierten Zeichenklasse.
^ Kontextoperator Das ^ *außerhalb* einer Zeichenklassendefinition bezeichnet den Anfang einer Zeile
$ Kontextoperator Ende einer Zeile
\b Kontextoperator Wortgrenze
\A Kontextoperator Beginn des Textes
\z Kontextoperator Ende des Textes
* Wiederholungsoperator 0-n Wiederholungen des vorangegangenen Zeichens (greedy!)
+ Wiederholungsoperator 1-n Wiederholungen des vorangegangenen Zeichens (greedy!)
? Wiederholungsoperator 0 oder 1 Wiederholungen des vorangegangenen Zeichens
{n,m} Wiederholungsoperator mindestens n, maximal m Vorkommen (Beispiel: {1,3})
{n,} Wiederholungsoperator mindestens n Vorkommen (Beispiel: {2,})
{,m} Wiederholungsoperator maximal m Vorkommen (Beispiel: {,3})
{n} Wiederholungsoperator exakt n Vorkommen (Beispiel: {2})
  • Um Metazeichen in Literale zu verwandeln, müssen ihnen Backslashes vorangestellt werden (sog. Maskierung): Der RE \[Haus\] „matcht“ den String „Haus“ zwischen eckigen Klammern, also [Haus]. Ohne die Maskierung würde es sich um eine Zeichenklasse, bestehend aus den Zeichen „H“, „a“, „u“ und „s“ handeln.

3. Greediness

Bei Wiederholungsoperatoren, die 0-n oder 1-n Wiederholungen beschreiben, spielt die „Greediness“ („Gierigkeit“) eine Rolle.

Beispiel: Man möchte in einem XML-Dokument die sog. Tags, also die mit < beginnenden und mit > endenden Strings „matchen“ (= finden). In natürlicher Sprache würde man formulieren: „Finde einen String, der mit einem < beginnt, daran anschließend eine beliebige Anzahl von beliebigen Zeichen enthält und mit einem > abgeschlossen wird„. In der formalen Sprache der regulären Ausdrücke würde man zunächst scheiben: <.*>. Durch die Greediness von * wird im folgenden Beispiel nicht die schließende spitze Klammer des ersten Tags (<h1>), sondern die des zweiten Tags (</h1>) gematcht:

Greediness von *. Die Farben von Regulärem Ausdruck und String korrespondieren.

Regulärer Ausdruck: <.*>
String:             <h1>Einführung in die Regulären Ausdrücke</h1>

Bei Verwendung eines nicht-„gierigen“ Wiederholungsoperators wird hingegen die schließende spitze Klammer des ersten Tags gematcht. Leider enthält das Basiskonzept der Regulären Ausdrücke keinen nicht-gierigen Wiederholungsoperator. In manchen Implementierungen existieren solche Operatoren jedoch als spezifische Erweiterung. Vim z.B. kennt den nicht-gierigen Wiederholungsoperator \{-}:

Non-Greediness von \{-}. Die Farben von Regulärem Ausdruck und String korrespondieren.

Regulärer Ausdruck: <.\{-}>
String:             <h1>Einführung in die Regulären Ausdrücke</h1>

Möglichkeit, non-greediness mit greedy-Operatoren */+ durch Negation nachzubilden (am Beispiel html-Tags: „nicht ‚>‘ „):

<[^>]*>

4. Alternativen

  • Alternativen werden angeben durch „|“ (sog. „pipe“):
[aeiou]|[3-8] Findet entweder einen Vokal oder eine Ziffer zwischen 3 und 8
aber|und  entweder „aber“ oder „und“

5. Gruppierung und Backreferencing

  • Die Definition einer Gruppierung erfolgt durch runde Klammern.
  • Eine Gruppe kann durch \1 (in manchen Implementierungen auch $1) angesprochen werden (sog. Backreferencing). Bei mehreren Gruppen, orientiert sich die Nummerierung an der Reihenfolge deren Definition von links nach rechts. Beispiele:
([A-Za-z])\1 Doppelungen („Geminate“) von beliebigen Buchstaben im ASCII-Bereich
(A)(B)\2\1 Zeichenfolge ABBA

6. REs im Editor Vim

Die Implementierung des Konzepts der regulären Ausdrücke im Editor Vim weist verschiedene Besonderheiten auf. Insbesondere müssen manche RE-Metazeichen mit Backslash maskiert werden. Außerdem werden Varianten von Standard-Metazeichen verwendet. Vim bietet überdies einige zusätzliche Metazeichen an, die den ursprünglichen regulären Ausdrücken fehlen.

Wichtige Vim-spezifische Varianten

Basis-RE Vim-Variante Bedeutung
+ \+ Wiederholungsoperator: 1-n
? \= Wiederholungsoperator: 0 oder 1
{m,n} \{m,n} Wiederholungsoperator: mindestens m, maximal n
{m} \{m} Wiederholungsoperator: exakt m
{m,} \{m,} Wiederholungsoperator: mindestens m
{,n} \{,n} Wiederholungsoperator: maximal n
| \| Alternative
(gruppe) \(gruppe\) Gruppierung

Nützliche Vim-spezifische Erweiterungen

\{-} non-greedy Wiederholungsoperator (0-n)
\_. beliebiges Zeichen, inklusive Zeilenende
\_s Leerzeichen oder Tabulator oder Newline
\< Anfang eines Wortes
\> Ende eines Wortes
  • Vim kann bei Suchen Groß- und Kleinschreibung berücksichtigen (:se noignorecase) oder auch nicht (:se ignorecase). Die entsprechende Einstellung beeinflusst auch die Suche nach regulären Ausdrücken. Bei Einstellung :se ignorecase „matcht“ der RE „Haus“ auch den String „HAUS“.
  • Kommando :nohl („no highlighting“ -> entfernt farbige Hervorhebung der gefundenen Muster)

7. Beispiele für REs (nach vim-Syntax)

Suche nach Zeichenmustern:

[ \n]\+ein[\n ]\+ „ein“ am Anfang, Ende oder in der Zeile
\<ein\> „ein“ am Anfang, Ende oder in der Zeile (\< und \> markieren Wortgrenze)
^$ Leere Zeilen
^$\n Leere Zeilen inklusive newline (wichtig bei Tilgung leerer Zeilen durch Ersetzung:)
^[ \t]*$ oder ^\s*$ Leere Zeilen mit Whitespace-Characters (Leerzeichen und Tabulatoren)
\([a-zA-Z]\)\1 Buchstabenwiederholungen (mm, nn, …)
[ \n]\([^ ]\+\)\_s\+\1 Wortwiederholungen (die die)
\(.\+\)[\_s\n]\+\1 Wiederholung von Wortgruppen
<\_.\{-}>

 XML-Tags (zeilenübergreifend)

[A-ZÄÖÜa-zäöü]{1,3}[ -]+[A-Za-z]{1,2} +[1-9][0-9]*[HE]?

Deutsche Kfz-Kennzeichen (Möglichkeit 1)

[A-ZÄÖÜ][A-ZÄÖÜ]*[A-ZÄÖÜ]*-[A-ZÄÖÜ][A-ZÄÖÜ]* [1-9][0-9]*[0-9]*[0-9]*[EH]*

Deutsche Kfz-Kennzeichen (Möglichkeit 2)

Ersetzungen:

:%s/\([.,!?;“«»]\)/ \1 /g Abtrennung von Satz- und Anführungszeichen durch Leerzeichen
:%s/^\s*$\n//g Löschen leerer Zeilen (auch mit Whitespace-Characters; wichtig: \n)
:%s/\s\+/\r/g Ersetzung von Whitespace-Characters durch Zeilenumbrüche (= Erzeugung einer Tokenliste)
:%s/\(\d\d\)\.\(\d\d\)\.\(\d\d\d\d\)/\3-\2-\1/g

Umwandlung von Datumsformaten nach dem Muster: 02.09.2020 -> 2020-09-02 (Möglichkeit 1)

:%s/\([0-3]?[0-9]\)\.\([01]?[0-9]\)\.\([0-9]{2,4}\)/\3-\2-\1, \2.\1.\3/g

Umwandlung von Datumsformaten nach dem Muster: 02.09.2020 -> 2020-09-02 (Möglichkeit 2; mit Mehrfachersetzung)

8. Nützliche Links

Screenshot des Portals regex101.com

Schreibe einen Kommentar