JavaScript/Objekte/RegExp
Reguläre Ausdrücke sind eine Möglichkeit, mittels eines Suchmusters in Zeichenketten nach Entsprechungen zu suchen. Suchtreffer können auch durch andere Inhalte ersetzt werden. Die Möglichkeiten von regulären Ausdrücken gehen weit über einfache Platzhalterzeichen hinaus, wie sie beispielsweise aus der LIKE Klausel von SQL oder aus den Verzeichnisauflistungen von Dateisystemen bekannt sind.
Der Begriff stammt aus der Theorie der formalen Sprachen, ein Thema aus der theoretischen Informatik, und geht auf Noam Chomsky zurück. Die heutigen RegExp Interpreter unterstützen allerdings auch Konstruktionen, die über die regulären Grammatiken von Chomsky hinaus gehen und sind daher streng genommen nicht mehr regulär. Trotzdem ist der Begriff "Reguläre Ausdrücke" nach wie vor üblich.
Reguläre Ausdrücke werden von vielen Programmiersprachen unterstützt. JavaScript orientiert sich dabei an der RegExp Implementierung der Sprache Perl 5.
Zur Nutzung von regulären Ausdrücken wird in JavaScript das RegExp Objekt verwendet. Es ist eine Konstruktorfunktion, um Objekte mit Suchmustern zu erzeugen.
Inhaltsverzeichnis
Eigenschaften und Methoden
RegExp.prototype stellt folgende Methoden und Eigenschaften bereit:
Eigenschaften
global
, ignoreCase
und multiline
sind Abfragen, ob das entsprechende Flag in flags
gesetzt ist. lastIndex
gibt die Position des letzten Suchtreffers an.
Die Methoden exec()
und test()
dienen zur Durchführung von Suchoperationen auf Zeichenketten. Darüber hinaus können RegExp Objekte auch an die folgenden JavaScript/Objekte/String-Methoden übergeben werden:
Reguläre Ausdrücke definieren
Um ein RegExp-Objekt zu erzeugen, haben Sie zwei Möglichkeiten.
- Aufruf des Konstruktors:
new RegExp(muster[, flags])
- Verwendung eines RegExp Literals:
/muster/flags
.
Das Muster, das an den RegExp Konstruktor übergeben wird, ist ein String und muss daher in Anführungszeichen eingeschlossen werden. Ein RegExp Literal ist kein String und steht nicht in Anführungszeichen.
Wie ein RegExp Muster aufgebaut wird, wird in den folgenden Abschnitten eingehend erläutert. Als flags
kann dem Konstruktor eine Zeichenkette übergeben werden, die einen oder mehrere der folgenden Buchstaben enthalten darf:
- d
- indices-Schalter (ab ECMAScript 2022). Erweitert das von exec() gelieferte Array um eine Eigenschaft namens
indices
, die die Positionen der Treffer im Original-String enthält - g
- Globale Suche, eine Suche liefert nicht nur den ersten Treffer, sondern ein Array aller Treffer
- i
- Suche ist case-insensitive
- m
- Multiline-Suche, bezieht sich auf die Funktion der ^und $ Steuerzeichen. Mehr dazu weiter unten.
- s
- dotAll-Funktion (ab ECMAScript 2018). Der Punkt findet auch Zeilenumbrüche (siehe [#Zeichenklassen|Zeichenklassen]) und ermöglicht die Verarbeitung eines mehrzeiligen Texts als eine lange Zeichenkette.
- u
- unicode-Schalter (ab ECMAScript 2015). Aktiviert Unicode-Funktionen in den Suchmustern
- y
- sticky-Schalter (ab ECMAScript 2015). Beginnt die Suche ab der Position, die in der lastIndex-Eigenschaft des RegExp-Objekts gespeichert ist. Ein Pattern mit ^ am Anfang trifft dann nichts, auch wenn Firefox das über mehrere Jahre (fälschlich) anders gemacht hat.
In den meisten Fällen ist das Suchmuster zum Zeitpunkt der Programmierung bekannt. Sie sollten es dann als RegExp Literalen notieren, damit die JavaScript Laufzeitumgebung es beim Laden des Scripts einmalig übersetzen und cachen kann. Den RegExp Konstruktor brauchen Sie nur, wenn Sie das Suchmuster zur Laufzeit aus einer Zeichenkette konstruieren müssen, oder die Flags dynamisch festlegen müssen. In diesem Fall sollten Sie zumindest versuchen, das RegExp Objekt nur einmal zu erzeugen und zu cachen. Eine RegExp Übersetzung ist eine zeitaufwändige Operation.
var rxSelf1 = new RegExp('[Ss]elfhtml');
var rxSelf2 = new RegExp('selfhtml', 'i');
var text = "Willkommen im SelfHTML Wiki";
text.match(rxSelf1); // liefert null - kein Treffer
text.match(rxSelf2); // liefert ["SelfHTML"]
var rxSelf3 = /[Ss]elfhtml/;
var rxSelf4 = /selfhtml/i;
// ...
Syntax des Suchmusters
Ein Regulärer Ausdruck besteht aus normalen Zeichen sowie Steuerzeichen für die Musterbildung. Ein normales Zeichen findet sich selbst (bzw. bei Verwendung des i Flags auch das entsprechende Gegenstück der Groß-/Kleinschreibung). Wenn man nach einem Steuerzeichen suchen will, muss man ihm im Suchmuster einen Backslash voranstellen.
Einfache Zeichen
Die meisten Zeichen des Zeichensatzes finden sich selbst. Um Zeichen zu finden, die über die Tastatur nicht eingegeben werden können, gibt es einige unterstützende Backslash-Sequenzen
Zeichencode | Erläuterung |
---|---|
\0 | findet das Nullzeichen (\x00, \u0000) |
\xnn | findet ein Zeichen mit dem durch den Hexadezimalwert nn angegebenen Zeichencode. \xnn ist eine Abkürzung für \u00nn. |
\unnnn | findet ein Unicode-Zeichen mit dem durch den Hexadezimalwert nnnn angegebenen Zeichencode. Beispiel: \u20AC für das Eurozeichen €. |
\b | Vorsicht Falle! \b kann ein Backspace-Zeichen darstellen, aber nur, wenn es innerhalb einer Zeichenklasse vorkommt: [\b]. Ein \b außerhalb einer Zeichenklasse sucht nach einer Wortgrenze (siehe Grenzprüfungen) |
\t | findet das Tabulator-Zeichen (\x09 oder \u0009) |
\n | findet das Zeilenumbruchzeichen (\x0a oder \u000a). Suchmuster, die \n enthalten, können zeilenübergreifend suchen. |
\v | findet das vertikale Tabulatorzeichen \u000b. Ob man heute noch Text findet, der ein VTab enthält, ist eine ganz andere Frage... |
\f | findet das Seitenvorschubzeichen \u000c. |
\r | findet das Wagenrücklaufzeichen \u000d. |
\cX | findet das Control-Zeichen X, z. B. \cG ist Ctrl-G oder \u0007. Control-Zeichen sind ein Relikt aus der Teletype-Zeit, wo die Zeichencodes \x01 bis \x1b wichtige Steueraufgaben hatten. \cA ist \x01, \cB ist \x02, und so weiter bis \cZ für \x1A. |
Zeichenklassen
Mit Zeichenklassen sucht man nach einem einzelnen Zeichen, das Element dieser Klasse ist. Einige Zeichenklassen sind vordefiniert, darüber hinaus kann man auch eigene Zeichenklassen definieren.
Innerhalb von Zeichenklassen müssen nur die Zeichen "[", "-", "]" und "^" mit einem Backslash gesichert werden.
Zeichenklasse | Erläuterung |
---|---|
. | ein Punkt findet ein beliebiges Zeichen außer \n |
[xyz] | Eine Folge von beliebigen Zeichen, die in eckigen Klammern eingeschlossen ist, findet ein Zeichen, das Teil dieser Folge ist. Innerhalb von eckigen Klammern haben lediglich drei Zeichen eine Sonderbedeutung, d. h. benötigen einen vorangestellten Backslash wenn man nach ihnen suchen will
Das Minuszeichen dient dazu, Zeichenbereiche zu definieren. [a-z] bezeichnet alle Zeichen c des Zeichensatzes, für die c >= 'a' und c <= 'z' gilt. Man kann auch mehrere solcher Intervalle definieren: [a-zA-Z] beschreibt alle Klein- und Großbuchstaben des lateinischen Alphabets. Intervalle, die "natürliche" Intervalle des Zeichensatzes überschreiten, sind mit Vorsicht zu betrachten, z. B. ist [A-z] gültig, findet aber auch die eckigen Klammern und den Unterstrich, weil die zwischen Z und a liegen. Die Angabe [a-Z] führt zu einem Laufzeitfehler, weil 'a' im Zeichensatz hinter 'Z' liegt. Ein Minus, das nicht von zwei normalen Zeichen umgeben ist, wird als literales Minuszeichen interpretiert. [A--] wäre beispielsweise ungültig, weil 'A' < '-' nicht erfüllt ist. [--A] würde alle Zeichen von '-' bis 'A' finden. Der Gebrauch von Backslash-Sequenzen, die einfache Zeichen repräsentieren, ist innerhalb von eckigen Klammern ebenfalls erlaubt. [\u0400-\u04ff] findet beispielsweise jedes kyrillische Zeichen. Darüber hinaus sind auch die Backslash-Sequenzen für Zeichenmengen erlaubt: [\s\d+\-*/] findet jeden ASCII-Leerraum, jede ASCII-Ziffer und die vier Grundrechenarten (das Minus hat einen Backslash vorangestellt, damit es keinen Bereich definiert). |
[^xyz] | Ein Zirkumflex-Zeichen hinter der linken eckigen Klammer erzeugt eine negierte Zeichenklasse. Damit findet man jedes Zeichen, das NICHT in den angegebenen Zeichen oder Zeichenfolgen enthalten ist. [^a-z] findet zum Beispiel jedes Zeichen, welches kein ASCII-Kleinbuchstabe ist. |
\s | findet alle Unicode Leerzeichen (white space), d. h. Leerzeichen, Umbrüche, Tabulatoren und typografische Sonderleerzeichen. Laut MDN ist \s eine Kurzform für [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. |
\S | findet alles außer den Zeichen von \s. Da Zeichenklassen-Angaben in anderen Zeichenklassen eingesetzt werden dürfen, kann man \S als Kurzform für [^\s] ansehen. |
\d | Dezimal numerische Zeichen ([0-9]) |
\D | alles außer dezimal numerischen Zeichen ([^0-9] bzw. [^\d]) |
\w | Alphanumerische Zeichen und der Unterstrich ([0-9a-zA-Z_]). Diese Klasse ist nicht für Unicode erweitert! |
\W | alles außer den alphanumerischen Zeichen bzw. Unterstrich ([^0-9a-zA-Z_] bzw. [^\w]) |
Alternative
Will man in einer Suchoperation verschiedene Varianten eines Suchmusters unterstützen, kann man mehrere Suchmuster durch den Alternativ-Operator |
hintereinander angeben. Wenn nur ein Teil des Suchmusters alternativ sein soll, kann der Alternativ-Operator auch innerhalb einer Klammer verwendet werden (siehe unten).
Quantifizierer (quantifier)
Quantifizierer dienen dazu, Wiederholungen in einem Muster zu definieren. Sie können hinter einzelnen Zeichen, hinter einer Angabe für eine Zeichenklasse oder hinter einer Klammergruppe (siehe unten) stehen. Entsprechend muss im Suchtext das Element, dem der Quantifizierer folgt, wiederholt vorkommen. Durch einen Wiederholfaktor von 0 lassen sich auch optionale Elemente im Suchmuster unterbringen.
Quantifizierer | Erläuterung |
---|---|
? | das vorstehende Element kommt nicht oder genau einmal vor |
* | das vorstehende Element kommt nicht oder beliebig oft vor |
+ | das vorstehende Element kommt mindestens einmal vor |
{n} | das vorstehende Element kommt genau n mal vor |
{n,m} | das vorstehende Element kommt n bis m mal vor |
{n,} | das vorstehende Element kommt mindestens n mal vor |
{,m} | GIBT ES NICHT! Verwenden Sie {0,m} für null bis m Vorkommen |
?? | nicht-gierige Version von ? |
*? | nicht-gierige Version von * |
+? | nicht-gierige Version von + |
{,}? | nicht-gierige Versionen von {0,m}, {n,m}, {n,} |
Gierigkeit
Standardmäßig erfassen Quantifizierer so viele Wiederholungen wie möglich, bis zur vorgegebenen Obergrenze. Dieses Verhalten wird als "gierig" (greedy) bezeichnet und kann gelegentlich zu unliebsamen Überraschungen führen. Folgendes Beispiel illustriert dieses Verhalten:
text.match(/<a.*>/g)
(Suche nach Zeichenfolgen, die mit „<a“ beginnen, gefolgt von beliebig vielen Zeichen und mit „>“ enden.)
Angewendet aufvar text = '<a href="#test1">test1</a>'
Das Suchmuster trifft nämlich sowohl auf
<a href="#test1">
als auch auf
<a href="#test1">test1</a>
zu.
Es wurde die längste der möglichen Zeichenketten zurückgeliefert.Für den Fall, dass dieses Verhalten nicht gewünscht ist, verwenden Sie die oben angegebene nicht-gierige Version des Quantifizierers.
text.match(/<a.*?>/g)
Gruppierung
Innerhalb von Regulären Ausdrücken kann man bestimmte Bereiche einklammern. Dabei wird zwischen Klammern, welche übereinstimmende Ausdrücke speichern (capturing group), und nicht speichernden Klammern (non-capturing group) unterschieden. Auf die gespeicherten Teile kann man auf zwei Arten zugreifen:
- Die match() Methode einer Zeichenkette und die exec() Methode einer RegExp liefern ein Array zurück. Dieses Array enthält auf Indexposition 0 den kompletten gefundenen Text, und auf den Indexpositionen 1-9 die ersten neun gespeicherten Übereinstimmungen.
- Die replace() Methode einer Zeichenkette kann als zweiten Parameter ein Ersetzungsmuster erhalten. In diesem Ersetzungsmuster können die ersten neun gespeicherten Ausdrücke als $1..$9 verwendet werden.
Eine non-capturing group erhält man, indem man hinter der öffnenden Klammer ?:
schreibt.
/Einen (.*) Tag/
var cap = "Sehr geehrte Frau Meier".match(/(Herr|Frau)\s+(\w+)/)
// cap enthält ["Frau Meier", "Frau", "Meier"]
var nonCap = "Sehr geehrte Frau Meier".match(/(?:Herr|Frau)\s+(\w+)/)
// nonCap enthält ["Frau Meier", "Meier"]
(?: )
dient lediglich der Gruppierung.Zusicherungen (assertions)
Normalerweise wird alles, worauf das Suchmuster passt, zum Teil des Suchergebnisses. Das ist aber nicht immer gewünscht, vielleicht möchte man jedes Wort finden, oder nur Worte denen ein Ausrufezeichen folgt, ohne dabei die Wortbegrenzung oder das Ausrufezeichen als Teil des Treffers zu bekommen. Dafür gibt es das Konstrukt der Zusicherungen. Vier davon sind Teil der Sprache, darüber hinaus kann man mit einem speziellen Gruppenkonstrukt einen kleinen Blick in die Zukunft werfen.
Zusicherung | Erläuterung |
---|---|
\b | definiert eine Wortgrenze. Das Muster /\bSelfHTML/ findet einen Treffer in "Hier ist SelfHTML" oder "Lies:SelfHTML", aber nicht in "MeinSelfHTML". Technischer formuliert: \b betrachtet das Zeichen, das gerade im Suchtext überprüft wird, und das, das links davon steht. Es prüft dann, ob diese Zeichen in die Zeichenklasse \w fallen. Ist diese Prüfung für genau eins der beiden Zeichen wahr, besteht eine Wortgrenze. |
\B | Umkehrung von \b. Ist nur dann erfolgreich, wenn das Zeichen an der aktuellen Position im Suchtext sowie das Zeichen links davon beide zu \w gehören oder beide nicht zu \w gehören. |
^ | Anfang des Suchtexts (beim m-Modifikator Anfang jeder Zeile) |
$ | Ende des Suchtexts (beim m-Modifikator Ende jeder Zeile) |
(?=lookaheadpattern) | Positive vorausschauende Zusicherung. Dies ist ein Blick in die Zukunft: es wird geprüft, ob ab der aktuellen Position ein bestimmtes Muster (das lookahead-pattern) folgt, ohne dabei die aktuelle Position zu verändern. Wenn ja, ist der look-ahead erfolgreich und der Mustervergleich kann weitergehen. Man kann ein Muster aber auch mit einem look-ahead beenden, um einen Treffer nur dann zu erzielen, wenn auf ein gefundenes Muster noch ein bestimmtes weiteres Muster folgt. |
(?!lookaheadpattern) | Negative vorausschauende Zusicherung. Ist dann erfüllt, wenn das lookahead-pattern nicht erscheint. |
"Hallo SelfHTML".match(/^SelfHTML/); findet keinen Treffer, SelfHTML steht nicht am Anfang
"Hallo SelfHTML".match(/SelfHTML$/); findet einen Treffer, weil SelfHTML am Ende steht
"Hallo SelfHTML".match(/\bHTML\b/); findet keinen Treffer, HTML ist kein eigenes Wort
"Hallo SelfHTML".match(/\BHTML\b/); findet einen Treffer, weil HTML Ende eines Wortes ist
"SelfHTML".match(/Self(?=HTML)/); // liefert [ "Self" ], nicht ["SelfHTML"]
"SelfPerl".match(/Self(?=HTML)/); // liefert null
"Self".match(/Self(?=HTML)/); // liefert null
(?= lookaheadpattern )
bewirkt, dass "Self" nur getroffen wird, wenn "HTML" dahinter steht."SelfHTML ist toll".match(/SelfHTML(?!!)/); // liefert [ "SelfHTML" ]
"Willkommen bei SelfHTML!".match(/SelfHTML(?!!)/); // liefert null
"Hello SelfHTML".match(/SelfHTML(?!!)/); // liefert [ "SelfHTML" ]
(?! lookaheadpattern )
bewirkt, dass "SelfHTML" nur getroffen wird, wenn kein Ausrufezeichen dahinter folgt.Ein zusammenhängendes Beispiel
<html> <head> <title>Test</title> <script type="text/javascript"> function Ausgabe (Wert) { const Ausdruck = /(\w.+)\s(\w.+)/; let match = Ausdruck.exec(Wert); if (match) alert(match[2] + ", " + match[1]); } </script> </head> <body> <form action=""> <input type="text" name="User" value="Vorname Zuname"> <input type="button" value="Ausgabe" onclick="Ausgabe(this.form.User.value)"> </form> </body> </html>
Das Beispiel zeigt, wie sich ein Name nach dem Schema "Vorname Zuname" unter Verwendung eines regulären Ausdrucks in das Schema "Name, Vorname" verwandeln lässt.
Das Beispiel enthält ein Formular mit einem Eingabefeld und einem Button. In dem Eingabefeld soll der Anwender seinen Namen in der Form "Vorname Zuname" eingeben. Deshalb ist das Feld auch schon so vorbelegt. Beim Anklicken des Buttons wird die Funktion Ausgabe()
aufgerufen, die im Dateikopf definiert ist. Als Parameter bekommt die Funktion den Inhalt des Eingabefeldes übergeben.
Innerhalb der Funktion wird ein regulärer Ausdruck (Suchausdruck) definiert, der in der Variablen Ausdruck gespeichert wird. Solche regulären Ausdrücke werden in einfache Schrägstriche /.../ eingeschlossen. Der reguläre Ausdruck im obigen Beispiel ist so zu lesen: Suche nach einer beliebigen Anzahl von aneinandergereihten Buchstaben ohne Ziffern und Satzzeichen und merke dir das Ergebnis (\w.+). Suche dann nach einem einzelnen Leerzeichen = \s. Suche dann noch einmal nach einer beliebigen Buchstabenreihenfolge und merke dir das Ergebnis (\w.+). Auf diese Weise wird das Schema "Vorname Zuname" gefunden. Die beiden Klammern um (\w.+) führen dazu, dass die beiden einzelnen Buchstabenreihenfolgen als einzelne Teile intern gemerkt werden. Später sind diese einzelnen gemerkten Teile separat ansprechbar.
Im Beispiel wird mit dem nächsten Befehl eine wichtige Methode des RegExp-Objekts auf den zuvor definierten regulären Ausdruck angewendet, nämlich die Methode exec(). Dadurch wird der Ausdruck "ausgeführt". Das Ergebnis ist ein Array von Zeichenketten. Es enthält an der Indexposition 0 den vollständigen getroffenen Text, an Indexposition 1 den Inhalt der ersten gemerkten Klammer und an Indexposition den Inhalt der zweiten gemerkten Klammer. Gibt der Anwender "Konrad Adenauer" ein, so ist das Ergebnis das Array [ "Konrad Adenauer", "Konrad", "Adenauer" ]. Falls der Anwender allerdings etwas eingibt, das nicht auf den Regulären Ausdruck passt, so ist das Ergebnis von exec() der Wert null
.
Durch die Anordnung mit dem Komma dazwischen bei der Ausgabe mit alert() erscheint das zuvor eingegebene "Vorname Zuname" dann in dem anderen Schema "Zuname, Vorname". Das Risko, mit match[1] oder match[2] auf undefinierte Array-Inhalte zuzugreifen, besteht nicht, da der Reguläre Ausdruck zwei capturing-groups enthält. Wenn es ein Ergebnis gibt, dann immer als Array mit 3 Elementen.
Umfangreichere Informationen über reguläre Ausdrücke finden Sie auf der Seite reguläre Ausdrücke in Perl.