5. Reguläre Ausdrücke

Reguläre Ausdrücke sind enorm wichtig, weil viele weitere Werkzeuge, wie Gulp oder WebPack, dies ohne weiteren Hinweis einfach nutzen. Es handelt sich um eine Technik zur Bildung von Suchmustern – also das Suchen von Zeichenfolgen in anderen Zeichenfolgen. Oft sind dies Dateien in einem Ordner oder Tags in einer HTML-Datei.

5.1 Einführung

Um ein Gefühl für reguläre Ausdrücke zu bekommen, will ich dir gleich ein Beispiel präsentieren, dass sicher bereits tausendfach zur Anwendung gekommen ist. Bei der Eingabe von Kundendaten wird oft die E-Mail-Adresse verlangt. Um Fehleingaben zu vermeiden, wäre eine Prüfung der Adresse auf korrekte Schreibweise sinnvoll. Eine Möglichkeit ist die Zerlegung der Adresse in ihre Bestandteile (vor und hinter dem @-Zeichen), die Analyse der Punkte und die Berechnung der Länge der Zeichen nach dem Punkt (dort steht die Toplevel_Domain). Das ist mit ein paar Schleifen und Abfragen sicher gut zu erledigen. Oder mit einem regulären Ausdruck:

^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)* @ [a-zA-Z0-9-]+\.([a-zA-Z]{2,3})$

Alles klar? Sicher kann niemand, der zum ersten Mal mit regulären Ausdrücken in Berührung kommt, diesen Ausdruck sofort lesen.

Der Sinn eines solchen Musters ist die Erkennung in einem Text. Reguläre Ausdrücke dienen als Vergleichsmuster für Zeichenketten. Der gesamte Ausdruck, verpackt in eine Skript- oder Programmiersprache, gibt dann true oder false zurück, je nachdem, ob das Muster gefunden wurde oder nicht. In der Praxis sind solche Konstrukte also immer in einem bestimmten Kontext zu sehen. In JavaScript würdest du dies so anwenden:

 1 var email = "joerg@krause.net";
 2 
 3 console.log(check(email));
 4 
 5 function check(email) {
 6   if (email.match(/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+\\
 7 .([a-zA-Z]{2,3})$/)) {
 8      return true;
 9   } else {
10      return false;
11   }
12 }

Hier wird der Ausdruck in die bei JavaScript typischen Begrenzungszeichen /Ausdruck/ eingebaut und der Vergleich erfolgt mit der Funktion match. Beachte, dass dies ein Literal in JavaScript ist – nicht eine Zeichenkette.

Musterskript in der Umgebung Repl.It
Musterskript in der Umgebung Repl.It

Kopieren oder Konstruieren?

Im Kapitel “Musterausdrücke” gehe ich umfangreich auf praktische Ausdrücke ein. Der Umfang ist so gewählt, dass du nicht nur trickreiche Ausdrücke kennenlernst, sondern auch das eine oder andere Problem durch simples Abschreiben lösen kannst. Weil das ungewöhnliche Fehlerquellen birgt, kannst du auf der Website zum Buch alle Beispiele herunterkopieren.

Wenn du professionell mit JavaScript arbeitest, solltest du dennoch versuchen, die Ausdrücke vollständig zu verstehen und gelegentlich selbst welche zu erstellen.

Und wie funktioniert das?

Wenn du Ausdrücke dieser Art analysierst, solltest du zuerst die Sonderzeichen erkennen und extrahieren. Die folgenden Sonderzeichen werden hier verwendet: ^, $, +, *, ?, [], (). Alle anderen Zeichen haben in diesem Zusammenhang keine besondere Bedeutung (das sind nicht sehr viele). Hier eine Übersicht über die Bedeutung:

Jetzt kannst du den Ausdruck schon gut zerlegen. Das @ steht offensichtlich für sich selbst, der Ausdruck besteht also aus zwei Teilen, einer vor und einer nach dem @:

1 ^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*
2 [a-zA-Z0-9-]+\.([a-zA-Z]{2,3})$

Der erste Teil steht vor dem @-Zeichen und muss mindestens ein Zeichen enthalten. Die erste Zeichengruppe [_a-zA-Z0-9-] definiert die zulässigen Zeichen und erzwingt mit dem + mindestens ein Zeichen. E-Mail-Namen dürfen aber auch Punkte enthalten, nur nicht an erster Stelle. Der Ausdruck kann also auch mit einem Punkt, gefolgt von weiteren Zeichen, fortgesetzt werden. (\.[_a-zA-Z0-9-]+) definiert solche Folgen aus einem Punkt und wiederum beliebig vielen (aber mindestens einem) Zeichen. Die ganze so definierte Gruppe (erkennbar an den runden Klammern) ist optional (0-mal) oder beliebig oft zu verwenden. Der zweite Teil besteht aus Zeichenfolgen (diesmal ohne den Unterstrich, der ist in Domainnamen nicht erlaubt). Dann muss ein Punkt folgen (deshalb folgt kein Mengenoperator), die Toplevel-Domain besteht aus Buchstaben und kann nur zwei oder drei Zeichen lang sein.

Auflösungshilfen

Der Ausdruck mag Ihnen unheimlich erscheinen, aber ist keineswegs perfekt (es gibt zulässige Fälle, die hier durchs Raster fallen). Er ist vor allem aber in dieser Form schwer erklärbar. Da noch größere Herausforderungen vor Ihnen liegen, möchte ich eine andere Form der Darstellung wählen:

 1 ^                         // Beginn am Zeichenkettenanfang
 2   [_a-zA-Z0-9-]           // Zeichengruppe definieren
 3   +                       // Ein- oder mehrfach
 4     (                     // Gruppe 1
 5        \.                 // Ein "echter" Punkt
 6        [_a-zA-Z0-9-]      // Zeichengruppe
 7         +                 // Ein- oder mehrfach
 8     )                     // /* Ende Gruppe 1 */ 
 9     *                     // Gruppe null- oder mehrfach
10   @                       // ein @-Zeichen
11   [a-zA-Z0-9-]            // Zeichendefinition
12   +                       // Ein- oder mehrfach
13   \.                      // ein "echter" Punkt
14     (                     // Gruppe 2
15         [a-zA-Z]          // Zeichendefinition
16         {2,3}             // Zwei oder drei Zeichen
17     )                     // /* Ende Gruppe 2 */
18 $                         // Ende der Zeichenkette

Das war doch schon leichter lesbar. Leider kannst du das so in JavaScript oder JSON nicht schreiben. Ich werden diese Form deshalb nur verwenden, um besonders verzwickte Ausdrücke aufzulösen. Wenn du mit einem Ausdruck nicht zurecht kommst, den ich im Buch verwende und nicht ausreichend erkläre, versuche diesen Ausdruck so aufzulösen.

5.2 Muster erkennen

In diesem Kapitel werden die grundlegenden Techniken anhand besonders einfacher Beispiel gezeigt. Dies genügt noch keinen praktischen Anforderungen, eignet sich aber gut als Grundlage eigener Experimente.

Grundlagen

Was passiert bei Auswerten eines Ausdrucks wirklich? Praktisch geht es immer darum, einen Text innerhalb eines umfangreicheren Textes zu suchen (Zeichenkette, Datei, Datenbank). Das ist aber nicht der eigentliche Anwendungsfall, denn so etwas erledigen Funktionen wie search (Suche einer Zeichenkette in einer anderen) effizienter. Reguläre Ausdrücke definieren Eigenschaften eines Suchtextes. Damit kann das Muster nicht nur auf einen bestimmten Suchtext passen, sondern auf eine ganze Reihe von Varianten. Suchen sowie Suchen und Ersetzen gewinnen so eine ganz andere Bedeutung.

Beim Suchen wird der reguläre Ausdruck genutzt, um eine Übereinstimmung festzustellen. Im Kontext einer Skriptsprache gibt der vollständige Ausdruck true oder false zurück. Da solche Vorgänge umfangreich sein können, werden manche reguläre Ausdrücke auch in Gruppen zerlegt. Dann gibt die Funktion auch die gefundenen Teile zurück. Diese wiederum können in weiteren Teilen desselben Ausdrucks oder später im Programm erneut verwendet werden. Auf diese sogenannten Referenzen gehe ich später detailliert ein.

Um die Darstellungen in diesem Buch möglichst kompakt zu halten, werde ich im folgenden Abschnitt einige Begriffe einführen, die immer wieder benötigt werden. Wenn du im Umgang mit diesen Begriffen vertraut bist, kannst du den Abschnitt überspringen.

Zeichen, Zeilen und Texte

Es wurden bereits Begriffe wie Zeichen, Zeile und Text verwendet. Wichtig ist das Verständnis des Begriffs Zeile. Zeilen enden mit einem Zeilenumbruch (da wo du in der Textverarbeitung oder im Editor Enter drückst). Viele Begrenzungszeichen reagieren auf Zeilenbegrenzungen. Dateien werden häufig auch zeilenweise eingelesen. Bei der Definition von Ausdrücken musst du also darauf in spezieller Weise reagieren, sonst werden Muster, die Zeilengrenzen überschreiten sollen, nicht erkannt.

Begriffe für reguläre Ausdrücke

In diesem Abschnitt werden einige weitere Begriffe eingeführt.

Metazeichen

Innerhalb eines regulären Ausdrucks können bestimmte Zustände in einer besonderen Weise gekennzeichnet werden. So wird der Beginn einer Zeichenkette mit ^ gekennzeichnet, das Ende dagegen mit $. ^ und $ sind also Metazeichen. Wenn du dagegen Metazeichen suchen möchten, musst du ein Backslash davor stellen:

Alle Metazeichen werden noch genau erklärt.

Literale

In JavaScript kannst du reguläre Ausdrücke in Literale schreiben. Solche Ausdrücke sind Teil der Sprache und müssen nicht aus Zeichenketten extrahiert werden. Das Literal ist der Schrägstrich /:

/[abc]/

Du kannst dies als Argument in Funktionen nutzen oder einer Variablen zuweisen. Du kannst auch Funktionen darauf anwenden:

1 var patt = /abc/;
2 var s = /abc/.toString();
3 console.log(s);
Zeichenklassen

Wenn du nach Zeichenfolgen oder Zeichen suchst, ist es oft effizienter, eine Zeichenklasse anzugeben. Zeichenklassen werden mit eckigen Klammern [abc] markiert, Dabei steht die gesamte Definition für ein Zeichen. Ein Wiederholungsoperator gibt an, ob und wie oft das Zeichen oder ein Zeichen aus der Klasse auftreten darf.

Zeichenklassendefinitionen werden durch Auflistung von zulässigen Zeichen gebildet, wobei auch Gruppen zulässig sind.

Referenzen

Teile regulärer Ausdrücke werden in temporären Speicherstellen abgelegt. Auf diese kannst du sich später im Ausdruck beziehen. Dadurch sind sehr komplexe Wiederholungen leicht zu realisieren. Referenzen nutzen den Backslash und eine Referenznummer (\4).

5.3 Metazeichen

Hier nun eine Übersicht über die Benutzung der Metazeichen.

Anfang, Ende und Grenzen

Die wichtigsten beiden Metazeichen kennst du schon aus den Grundlagen:

Wie ist das zu verstehen? Wenn du nach dem Wort “Auto” suchen, dann muss das “A” am Anfang stehen, das “o” dagegen am Ende. Du würdest einen solchen Ausdruck also ^Auto$ schreiben. Darf das Wort “Auto” dagegen irgendwo im durchsuchten Text auftreten, setze die Metazeichen ^ und $ nicht.

1 var patt = /^Auto$/;
2 console.log(patt.test("Auto"));
3 console.log(patt.test("Automatik"));
4 
5 var patt2 = /Auto/;
6 console.log(patt.test("Da ist unser Auto, ein VW."));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Das Ende ist meist das Ende der Zeile. Dies gilt nicht, wenn in umgebenden Schaltern andere Bedingungen eingestellt werden. Darauf gehe ich in Kapitel 3 ein.

Wortgrenzen sind Übergänge zu einem Wort. Als Wortgrenze zählt ein Leerzeichen, Komma, Punkt usw. Das spezielle Symbol \b reagiert darauf, beschreibt jedoch keine Zeichenstelle, sondern quasi den “Bereich” zwischen dem Leerzeichen und dem ersten Wortzeichen.

/\bko erkennt “ko” in dem Satz “Das ist kompliziert.”. Das Leerzeichen vor dem “ko…” erzeugt die Wortgrenze.

Ein beliebiges Zeichen

Oft wird an einer bestimmten Stelle ein Zeichen erwartet, egal um welches es sich handelt. Es wäre mühevoll, immer mit dem gesamten Zeichenvorrat zu operieren, deshalb gibt es ein spezielles Metazeichen dafür:

. steht für genau ein beliebiges Zeichen

Du kannst nun “Auto” in verschiedenen Kontexten suchen und dazu so vorgehen:

.uto findet “Spielzeugauto”, “Auto”, “Automatik” usw., aber auch “Distributor” (was sicher nicht immer erwünscht ist).

1 var patt = /.uto/;
2 console.log(patt.test("Auto"));
3 console.log(patt.test("Automatik"));
4 console.log(patt.test("Distributor"));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Ohne Zeichen

Angenommen du suchst leere Zeilen in einer Datei, dann sollte der folgende Ausdruck dies erledigen:

^$

So einfach? Sicher, die Zeile hat einen Anfang (den hat jede Zeile), der mit ^ erkannt wird, dem Anfang folgt unmittelbar das Ende $, dazwischen ist nichts, also muss die Zeile leer sein.

Sinnlos ist dagegen ein einzelnes ^ als Suchmuster. Dies markiert einen Zeilenanfang, diese Bedingung trifft aber auf jede Zeile zu.

5.4 Zeichenklassen

Zeichenklassen definieren Gruppen von Zeichen.

Einer aus vielen

Zeichenklassen werden durch eckige Klammern markiert. Ohne weitere Metazeichen oder Wiederholungsoperatoren wird nur ein Zeichen aus der definierten Klasse erkannt. Zeichenklassen können durch bloßes Aufzählen oder durch Gruppenbildung definiert werden, letzteres durch das Minuszeichen:

Die Reihenfolge spielt nur bei Gruppen ein Rolle. Ansonsten ist [a-fA-F] und [A-Fa-f] identisch.

1 var patt = /[a-f]+/;
2 console.log(patt.test("Auto"));
3 console.log(patt.test("42"));
4 console.log(patt.test("12 Tage"));
5 console.log(patt.test("borgen"));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Negation

Die gesamte Definition kann negiert werden, wenn am Anfang das Zeichen ^ gestellt wird. Du siehst richtig; das Zirkumflex hat in der Zeichenklassendefinition eine andere Bedeutung (ist auch ein anderer Kontext). Das macht reguläre Ausdrücke so tückisch, aber auch so spannend.

Diese besondere Bedeutung hat das ^ allerdings nur, wenn es unmittelbar der öffnenden Klammer folgt. Die folgende Form entspricht lediglich ein paar speziellen Zeichen:

Ziffern

Häufig wird nach Ziffern gesucht. Diese können mit oder ohne Vorzeichen und Dezimalpunkt oder -komma geschrieben werden. Folgende Definitionen bieten sich dazu an:

Datum und Zeit

Für Datums- und Zeitangaben wären folgende Definitionen möglich:

Das letzte Beispiel zeigt, das diese Klasse nicht so sinnvoll ist, denn theoretisch wären auch Zeitangaben wie “a9” oder “p0m” zulässig.

1 var patt = /[0-9:amp]/;
2 console.log(patt.test("12am"));
3 console.log(patt.test("4:17"));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Zeichenketten

Bei Zeichenketten kann man mit Zeichenklassen gezielt auf Groß- und Kleinschreibung reagieren:

Wenn die Schreibweise eines Namens nicht eindeutig ist, kann man darauf folgendermaßen reagieren:

5.5 Abkürzungen

Die folgende Tabelle gibt eine Überblick über die unterstützten Metazeichen:

Tabelle: Abkürzung durch Metazeichen
Abkürzung Beschreibung
\t Tabulatorzeichen
\n Newline (Neue Zeile)
\r Return (Wagenrücklauf)
\f Formfeed (Seitenvorschub)
\v Vertikaler Tabulator
\s White-Space (eines der im Druck nicht sichtbaren
  Zeichen, also \t, Leerzeichen, \n, \r, \f)
S Negation von \s
\w Wortzeichen (Zeichen, aus denen Wörter bestehen,
  konkret [_a-zA-Z0-9]
W Die Negation von \w
\d Ziffer (engl. digit), entspricht [0-9]
D Negation von \d
\b Wortgrenze, als Anfang oder Ende eines Wortes
  zählen alle Zeichen, die nicht zur Abkürzung \w gehören.
B Negation der Anweisung \b
\0 Null-Zeichen (physische 0)
\xxx Zeichenwert, dargestellt durch eine oktale Zahl
\xdd Zeichenwert in der hexadezimalen Form
\uxxxx Unicode-Zeichen in hexadezimaler Schreibweise
\cxxx Steuerzeichen, ASCII-Wert

5.6 Wiederholungsoperatoren

Die bisher gezeigten Definitionen sind immer auf ein Zeichen bezogen. Wichtiger ist dagegen die Auswahl einer bestimmten Anzahl Zeichen. Dazu werden Wiederholungsoperatoren eingesetzt. Einige spezielle will ich wegen der besonderen Häufigkeit in regulären Ausdrücken zuerst zeigen. Eine allgemeinere Definition folgt danach.

Allgemeine Wiederholungsoperatoren

Neben der allgemeinen Aussage, ob Zeichen erlaubt sind oder nicht, wird in vielen Fällen eine bestimmte Anzahl erwartet. Dazu wird hinter das Zeichen, die Zeichenklassendefinition oder die Zeichengruppe folgender Ausdruck gesetzt:

Die bereits gezeigten Metazeichen kann man mit dem allgemeinen Wiederholungsoperator auch darstellen. Das ist logisch, denn die Zeichen *, + und ? sind nur Abkürzungen der folgenden Ausdrücke:

Wiederholungsoperatoren eignen sich hervorragend zur Bestimmung korrekter Längen bei Eingabewerten. Angenommen du hast ein Formular mit einem Feld “postleitzahl”:

1 <form>
2   <input type="text" name="postleitzahl" value="">
3   <input type="submit">
4 </form>

Dann wäre folgender Ausdruck geeignet:

 1 <script>
 2 var re = /^[0-9]{5}$/;
 3 var feld = "12683";
 4 var checkplz = re.exec(feld);
 5 if(!checkplz) {
 6   alert("Die Postleitzahl " + checkplz + " ist nicht korrekt.");
 7 } else {
 8     console.log(checkplz)
 9 }
10 </script>
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Auf einen Blick

Tabelle: Wiederholungsoperatoren
Operator Bedeutung Beschreibung
? 0 – 1 Kein oder ein Zeichen
* 0 – ∞ Kein oder beliebig viele Zeichen
+ 1 – ∞ Mindestens ein oder beliebig viele Zeichen
{zahl} Zahl Genau zahl Zeichen
{min,} Min – ∞ Mindestens min Zeichen
{,max} 0 – Max Kein oder maximal max Zeichen
{min, max} Min – Max Minimal min bis maximal max Zeichen

5.7 Referenzen und Gruppen

Die bisherigen Elemente sollten keine großen Probleme bereitet haben. Für komplexere Auswertungen sind Kombinationen aus Metazeichen und Zeichenklassen nicht ausreichend flexibel. Auf Schleifen zum Durchsuchen von längeren Zeichenketten mit Wortwiederholungen kannst du noch nicht verzichten.

Referenzen

Solche Wiederholungen werden in regulären Ausdrücken durch Referenzen erreicht. Praktisch wird damit durch ein besonderes Metazeichen \1, \2 usw., auf vorher markierte Teile verwiesen. Die Markierung selbst erfolgt durch runde Klammern (…).

Besondere Probleme bereitet dabei immer wieder die Zählung der Klammern, besonders wenn alle Arten von Klammern vielfältig verschachtelt werden. Der Regex-Compiler geht dabei ganz pragmatisch vor. Es werden nur die öffnenden (linken) Klammern durchlaufend gezählt. Die erste öffnende Klammer wird also dem Metazeichen \1 zugewiesen, die zweite \2 usw. Die meisten Umgebungen erlauben bis zu neun Referenzen, einige Implementierungen (wie die von JavaScript) aber auch bis zu 99.

Gruppierungen

Die Gruppierung alleine kann auch benutzt werden, um die Wiederholungsoperatoren auf mehrere zusammenhängende Zeichen anzuwenden. Die Referenz ist dann quasi ein Nebeneffekt, auf den man Bezug nehmen kann oder nicht.

Einfache Gruppen

Wenn du eine bestimmte Zeichenfolge wiederholen möchtest, genügt der Einsatz der Gruppierung:

1 var patt = /(ab)+/;
2 console.log(patt.test("abc"));
3 console.log(patt.test("abcabc"));
4 console.log(patt.test("aacbb"));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts
Umschließende Zeichen

Eine gute Anwendung ist die Suche nach Ausdrücken, die mit einem Zeichen umschlossen sind. Das kommt in Programmtexten häufig vor. Der folgende Ausdruck sucht Worte heraus, die in Anführungszeichen stehen, dabei soll folgende Regel gelten:

Eine mögliche Lösung wäre:

/^(["']){1}.*\1$/

Wie funktioniert das? Am Anfang der Zeichenkette ^ steht ein “ oder ein ‘ ["']. Diese Zeichenklasse darf nur einmal auftreten {1}. Dann können beliebig viele Zeichen .* folgen, bis am Ende $ wieder das Anführungszeichen vom Anfang steht \1. Ohne Referenzen wäre das kaum lösbar.

1 var patt = /^(["']){1}.*\1$/;
2 console.log(patt.test("\"Wort Wort Wort\""));
3 console.log(patt.test("\"Wort Wort Wort\'"));
4 console.log(patt.test("\'Wort Wort Wort\'"));
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

Das folgende Beispiel sucht einfach doppelte Wörter im Text:

/\b((\w+)\s+\2)+/

Der Ausdruck beginnt mit einer Wortgrenze \b, dann folgt der sich insgesamt wiederholende Ausdruck ((..)..)+. Der Inhalt ist getrennt zu betrachten. Die Folge (\w+)\s+ erkennt Wörter, die durch Leerräume getrennt sind. Dabei darf ein Whitespace nur auf ein ganzes Wort folgen. Damit das doppelte Wort erkannt wird, nimmt der Ausdruck Bezug auf die Wortdefinition. Diese befindet sich in der zweiten öffnenden Klammer, also wird \2 verwendet.

1 var patt = /\b((\w+)\s+\2)+/;
2 console.log(patt.test("Script Script ist doppelt"));

Vorwärtsreferenzen

Es kommt vor, dass Ausdrücke nur dann erkannt werden sollen, wenn bestimmte Zeichen davor oder danach erscheinen. Diese Zeichen davor oder danach sind jedoch selbst nicht von Interesse. Der Ausdruck wird also etwas um die Suchstelle “herum” suchen. Du erreichst dies mit den folgenden Kombinationen:

1 var patt = /(\d{1,3})(?=d)/;
2 var text = "Dauer: 16d";
3 var test = patt.exec(text);
4 console.log("Tage: " + test[0]);
Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts

In diesem Beispiel werden ein- bis dreistellige Zahlen nur erkannt, wenn ein “d” folgt.

5.8 Die JavaScript-Funktionen

Javascript stellt ein Objekt RegExp bereit. Das Objekt entsteht entweder durch den new-Operator oder das //-Literal. Außerdem kennen einige Zeichenkettenfunktionen reguläre Ausdrücke.

Das RegExp-Objekt

Zuerst findest du hier eine systematische Übersicht. Danach folgen entsprechende Beispiele.

Methoden

Folgende Methoden sind benutzbar:

Neben den Methoden des RegExp-Objekts können auch viele andere Funktionen in JavaScript mit Ausdrücken umgehen, unter anderem die String-Funktionen.

Die Methode exec gibt ein Objekt zurück, dass folgendes enthält:

Neben den Angaben, die als Ergebnis zurückgegegen werden, enthält auch das ursprüngliche RegExp-Objekt weitere Informationen. Dazu gehört auch die Fähigkeit, durch weitere Elemente der Trefferliste zu iterieren.

Das folgende Script enthält einen sehr einfachen Ausdruck. Dafür führt er zu mehreren Treffern. Das sukzessive Aufrufen desselben Ausdrucks setzt intern einen Zeiger weiter, sodass die do-Schleife alle Treffer durchläuft.

 1 var text = "Da sucht man alle Angaben von a ";
 2 var patt = /a/g;
 3 var match = patt.exec(text);
 4 console.log(match[0] + " gefunden bei Pos. " + match.index);
 5 
 6 match = patt.exec(text);
 7 do {
 8     match = patt.exec(text);
 9     if (!match) break;
10     console.log(match[0] + 
11                 " gefunden bei Pos. " + match.index);
12 } while(true);

Die Ausgabe sieht nun folgendermaßen aus:

Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts
Eigenschaften

Einige Eigenschaften helfen dabei, mit den Informationen aus dem Ausdruck flexibel umgehen zu können:

Hier folgt ein Skript, da zeigt, wie der interne Zeiger weiterläuft:

 1 var text = "Da sucht man alle Angaben von a ";
 2 var patt = /a/g;
 3 var match = patt.exec(text);
 4 console.log(match[0] + " gefunden bei Pos. " + match.index);
 5 
 6 match = patt.exec(text);
 7 do {
 8     match = patt.exec(text);
 9     if (!match) break;
10     console.log(match[0] + " gefunden bei Pos. " + match.index);
11     console.log( "Suche Weiter bei Pos. " + patt.lastIndex);
12 } while(true);

Die Ausgabe sieht nun folgendermaßen aus:

Abbildung: Ausgabe des Skripts
Abbildung: Ausgabe des Skripts
Dynamische Eigenschaften

Gruppen, die in einem Ausdruck definiert werden, stehen als dynamische Eigenschaften des Objekts RegExp zur Verfügung. Die Namen lauten $1 bis $9, wobei jede öffnende Klammer zählt. Du kannst die Zählung einer Klammer unterdrücken, indem Du diese (?:) schreiben (der Doppelpunkt modifiziert das Verhalten).

1 var patt = /(abc)|(def)/;
2 var text = "anton def";
3 console.log(patt.test(text));
4 console.log(RegExp.$1);

Die zweite Zeile gibt den Inhalt der Klammer zurück, die im Suchmuster gefunden wurde, hier also den Wert “def”.

Literalschreibweise direkt nutzen

Am einfachsten ist die Nutzung der Literal-Schreibweise:

1 var patt = /web/i;
2 patt.test("Besuche unsere Web-Kurse!"); 

Dieser Ausdruck gibt true zurück. Würde das i am Ende entfallen, entsteht false.

Die Methoden lassen sich auch direkt ans Literal anbinden. Hier ein Beispiel für exec:

1 /web/i.exec("Besuche unsere Web-Kurse!"); 

Zurückgegeben wird nun ein Objekt mit dem Treffer “Web” an Position 0, der Trefferstelle in der Eigenschaft index, hier der Wert 15 und dem Suchtext in der Eigenschaft input. Wird nichts gefunden, gibt die Methode exec den Wert null zurück.

Willst du das Objekt direkt anlegen, sieht das folgendermaßen aus:

1 var patt =  new RegExp("pattern");
Verarbeitungsoptionen

Einige Optionen werden nicht als Teil des Ausdrucks, sondern als Option der ausführenden Methode übergeben. In JavaScript stehen diese Optionen am Ende des Ausdrucks nach dem schließenden /-Zeichen:

var pattern = /[A-Z]/i

Unterstützt werden folgende Optionen:

Zeichenkettenfunktionen

Es folgen einige Beispiele, die die Syntax in JavaScript näher erläutern. Sie zeigen, dass reguläre Ausdrücke auch in anderen Funktionen einsetzbar sind.

Übersicht

Reguläre Ausdrücke lassen sich indirekt über Zeichenkettenfunktionen nutzen. Zur Verfügung stehen folgende Funktionen:

1 var str = "Besuche unsere Web-Kurse";
2 var res = str.search(/Web/i); 
3 console.log(res);

Die Variable res enthält den Wert 15. Es wird also der Index des Treffers angezeigt. Wird kein Treffer gefunden, wird -1 zurückgegeben.

Wird statt des Index nur ein boolesches Ergebnis benötigt, eignet sich match:

1 var str = "Besuche unsere Web-Kurse";
2 var res = str.match(/Web/); 
3 if (res) {
4   console.log("Treffer");
5 } else {
6   console.log("Kein Treffer");
7 }

Der Ausdruck ist erfüllt und es wird Treffer ausgegeben.

Analog funktioniert replace:

1 var str = "Besuche unsere Web-Kurse";
2 var res = str.replace(/Web/i, ".NET"); 
3 console.log(res);

Die Variable res enthält den Wert Besuche unsere .NET-Kurse.