Reguläre Ausdrücke

Reguläre Ausdrücke sind Muster, die verwendet werden, um Zeichenkombinationen in Strings finden zu können. In JavaScript sind reguläre Ausdrücke Objekte. Dazu werden Methoden des Objekttyps RegExp zur Verfügung gestellt.

Von der theoretischen Informatik wissen wir, dass reguläre Ausdrücke über einem Alphabet definiert sind als die Menge von Zeichenketten über dem Alphabet, die sich durch Auswahl, Verkettung und Abschluss bilden lassen. In JavaScript wird als Alphabet der Zeichensatz des Rechners genommen. Zusätzlich gibt es Sonderzeichen, wie Steuerelement (Tabulator, Zeilenvorschub usw.). Neben der normalen Verkettung und dem Abschluss kann man Längenbeschränkungen und andere Optionen angeben.

Reguläre Ausdrücke in JavaScript sind ähnlich zu den aus Perl oder PHP4 bekannten Suchmustern.

Verwendung reguläre Ausdrücke

In JavaScript kann man reguläre Ausdrücke auf zwei Arten nutzten:

Zunächst werden wir die erste Methode verwenden, dann werden wir mit der Klasse RegExp arbeiten.

Ein Benutzer soll in einem Formular eine eMail Adresse eingeben. Dazu wird das Zeichen "@" gesucht.

Beispiel 6.1-1

Im Beispiel wird (in der Funktion test) zunächst ein regulärer Ausdruck mit "var reg = /@/;"  definiert. Der Aufruf der Methode "exec" prüft, ob das Muster (/@/) im String vorkommt.

eMial Adressen sind etwas komplexer aufgebaut. So sind eMail Adressen der FHD etwa durch den regulären Ausdruck

    / [a-z]+@fbi\.h-da\.de /i

definiert.

Beispiel 6.1-2

Nun werden wir den Aufbau von regulären Ausdrücken besprechen.

Einfache reguläre Ausdrücke

In JavaScript wird ein regulärer Ausdruck einfach in die Zeichen "/" eingeschlossen.

Jedes Zeichen des Zeichensatzes selbst ist ein regulärer Ausdruck.

    /a/   /* a ist ein regulärer Ausdruck */
    /b/   /* b ist ein regulärer Ausdruck */

Eine Verkettung von regulären Ausdrücken ist selbst wieder ein regulärer Ausdruck. 

    /ab/ 
    /JavaScript Kurs!/   

Um einfach zum Ausdruck bringen zu können, dass Groß- oder Kleinschreibung nicht von Interesse ist, kann man nach dem "schließenden /" den Modifikator "i" angeben. Ein weiteres Modifikationssymbol ist "g". Durch ihm wird bei der Methode exec()ein Array von Teilstrings zurückgeliefert, die alle auf den regulären Ausdruck passen.

regulärer Ausdruck passt z.B. auf

/ab/i

ab
AB
aB
Ab

Besondere Zeichen

Die Zeichen "." und "+" haben eine besondere Bedeutung. "." passt auf jedes Zeichen (außer dem Zeilenumbruch); durch ein "+" wird zum Ausdruck gebracht, dass das vorherige Zeichen beliebig oft wiederholt wird.

regulärer Ausdruck passt z.B. auf

/ab.d/

abcd
ab1d
abCd

/ab+x/

abbx
abbbbbbbx

/ab.+x/

ab1111111111x
ab   x
abx

Neben diesen Zeichen haben folgende Zeichen ebenfalls eine besondere Bedeutung:

    \ | ( ) [ { ^ $ * ? . +

Soll ein solches Zeichen selbst in einem regulären Ausdruck als Zeichen erscheinen, so ist es durch einen Backslash "\" in seiner Rolle als besonderes Zeichen zu "entwerten".

regulärer Ausdruck passt z.B. auf

/a\+b/

a+b

/a\\b/

a\b

/a\\+/

a\
a\\\\\\

Mit dem Backslash sind auch besondere Zeichen einzuleiten; für einen Tabulator steht z.B "\t".

Nachfolgend sind diese Zeichen beschrieben.

Zeichen Bedeutung

\n

Zeilenvorshub

\r

Wagenrücklauf

\t

Tabulator

\v

Vertikaltabulator

\f

Seitenvorschub

\d

eine Ziffer (== [0-9])

\D

ein Zeichen, dass keine Ziffer ist (==[^0-9])

\w

alphanumerisches Zeichen (==[a-zA-Z])

\W

nicht alphanumerisches Zeichen (==[^a-zA-Z])

\s

whitespace (==[\t\v\n\r\f])

\S

kein whitespace  (==[^\t\v\n\r\f])

.

beliebiges Zeichen

Im folgenden Beispiel wird geprüft, ob in der Eingabe nach beliebigen Zeichen, ein Wort aus Ziffern enthalten ist.

Beispiel 6.1-3

Multiplikatoren

Multiplikatoren (oder Quantifikatoren) erlauben es, in einem regulären Ausdruck anzugeben, wie oft ein Muster vorkommen soll. "+" und "*" haben wir bereits gesehen; die Modifikatoren sind in der u.a. Tabelle zusammengefasst:

Multiplikator Bedeutung

{m,n}

mindestens m-mal, höchstens n-mal

{m,}

mindestens m-mal

{m}

genau m-mal

*

0 oder mehrere (=={0,})

+

1 oder mehrere (=={1,})

?

0 oder 1 mal (=={0,1})

Der reguläre Ausdruck

    /a{1,3}bc/

passt z.B. auf die Zeichenfolgen:

    abc
    aabc
    aaabc
    aaaabc
    aaabcbc
    aaaxyaaabc

aber nicht auf

    bc
    aaxbc
    aaabxc

Oft ist es nicht nur interessant zu wissen, ob das Muster zu finden ist, sondern auch wo es in einer Eingabe zu finden ist. Die Methode exec() hat als Rückgabe den Teil des Strings, auf den der reguläre Ausdruck passt, bzw. null, wenn er nicht gefunden wird. (null wird als false interpretiert, deshalb war die if-Abfrage möglich)

Dies ist im nächsten Beispiel demonstriert.

Beispiel 6.1-4

Wir werden die Methode exec() später noch genauer diskutieren, um z.B. nicht nur das erste, sondern auch die restlichen Auftreten der gefundenen Muster bearbeiten zu können.

Zusammenfassen von Zeichen

Im regulären Ausdruck /abc+/ bezieht sich der Multiplikator "+" das Zeichen "c". Im allgemeinen bezieht sich ein Multiplokator auf den davor stehnden regulären Ausdruck. Dies ist ja kein Widerspruch, "a" ist selbst ein regulärer Ausdruck. Will man, dass der Multiplikator "+" sich auf die Zeichenkette "abc" bezieht, so muss man Klammern: /(abc)+/.

/(abc)+/ passt z.B. auf

xabcabc
xabcabcabc
ababcabcabc123

Alternativen

Alternativen werden durch das Zeichen "|" zu Ausdruck gebracht.

Wenn r1 und r2 reguläre Ausdrücke sind, so ist auch r1|r2 ein regulärer Ausdruck.

Beispiel:

/Schuette|Schütte/ passt auf "Schuette" und "Schütte"

/Sch(ue|ü)tte/ passt auf "Schuette" und "Schütte"

Begrenzer

Nehmen wir an, wir wollen ein Muster angeben, so dass nur Worte erkannt werden. In diesem Fall sind besonderen Begrenzungszeichen hilfreich, z.B das Zeichen "\b", das auf eine  Wortgrenze passt.

Diesen Begrenzer (oder Anker genannt) werden im folgenden Beispiel verwendet, um eine Login Seite aufzurufen.

Beispiel 6.1-5

Bei Eingabe von "aschuette" wird die Defaultseite geladen, denn der reguläre Ausdruck passt nicht auf die Eingabe, wenn "a schuette" eingegeben wird, wird meine Startseite geladen.

Folgende Tabelle listet die Begrenzer auf:

Zeichen Bedeutung
^ Anfang eines Strings
$ Ende eines Strings
\b Wortgrenze
\B keine Wortgrenze

Zeichenklassen

Eine Menge von Zeichen kann man definieren, indem man die Zeichen in geschweifte Klammern setzt. So passt

/[0123456789]/

oder

/[0-9]/

auf Ziffern.

Buchstaben sind somit durch den Ausdruck

[a-zA-Z]

beschrieben.

Vokale werden demnach durch folgenden Ausdruck beschrieben:

/[aeiou]/

Das folgende Beispiel verdeutlicht, wie mit regulären Ausdrücken geprüft werden kann, ob eine Eingabe ausschließlich aus Ziffern besteht.

/^[0-9]+$/

Im letzten Beispiel bedeutet "^" Anfang des Strings. Verwendet man das Zeichen innerhalb einer Zeichenklasse, so hat es die Bedeutung von "NICHT". So passt

/[^0-9]/

auf Strings, die keine Ziffer enthalten.

Klammern

Mit runden Klammern kann man Zeichen zu einem Ausdruck zusammenfassen. Dadurch wird ein interner Zwischenpuffer angelegt, der später im Ausdruck verwendbar ist, um das gefundene Muster zu referenzieren.

Die gefundenen Teilstrings können dabei durch "\1", "\2" usw. verwendet werden.

/(abc) XXX \1/

passt auf Strings, die mit "abc" beginnen und enden.

/(ab*c) XXX \1/

passt z.B. auf folgende Strings:

ac XXX ac
abc XXX abc
abbc XXX abbc

nicht jedoch auf

ac XXX abc
abc XXX ac
abbc XXXX abbc

Durch folgenden regulären Ausdruck lassen sich einfache XML Tags finden:

/<(.+)>.*<\/\1>/

Beispiel 6.1-6

Übung 6.1

Wie muss ein regulärer Ausdruck definiert sein, damit folgende Muster erkannt werden:

  1. deutsche Postleitzahlen
  2. Namen, die aus Vor- und Zuname bestehen
  3. internationale Rufnummern

Die Klasse RegExp

Bisher wurden reguläre Ausdrücke "literal" definiert. Nun werden wird die Klasse RegExp diskutieren.

Der Konstruktor RegExp

Durch

    reg = /abc/i

konnte eine Variable deklariert werden, die als Wert den regulären Ausdruck zugewiesen bekommt.

Mit dem Operator new kann die o.a. Variable wie folgt deklariert werden:

    reg = new RegExp("abc", "i")

Bevor ein regulärer Ausdruck bearbeitet werden kann, muss er vom JavaScript Interpreter übersetzt werden. Der Zeitpunkt der Übersetzung ist bei beiden o.a. Methoden der Definition des regulären Ausdruckes unterschiedlich:

Methoden

Die Klasse RegExp hat drei Methoden:

compile

Mit der Methode compile(regexp, mod) wird der reguläre Ausdruck regexp übersetzt. mod ist dabei ein String von Modifikatoren. Dadurch ist es möglich, einen regulären Ausdruck zur Laufzeit zu ändern:

var red = new RegExp("abc","gi");

....

if (...) reg.compile("xyz", "i")

...

exec

Die Methode exec(str)durchsucht str nach dem Teilstrings, die zum regulären Ausdruck passen. Dabei wird null zurückgeliefert, wenn der das Muster nicht gefunden wird, ansonsten wird ein Array mit folgenden Informationen zurückgegeben:

Element Beseutung
index Position des ersten gefundenen Zeichens des Musters in str
input der String, auf den der reguläre Ausdruck angewendet wurde
[0] der Teilstring, der als Letztes gefunden wurde
[1], [2], ... Teilstrings, die durch Verwendung von Klammern gefunden wurden (\1, \2, ...)

Nach der Ausführung der Methode exec haben die Eigenschaften des RegExp-Objektes folgende Werte:

Eigenschaft Wert
global gibt an, ob Modifikator "g" verwendet wurde
ignoreCase gibt an, ob Modifikator "i" verwendet wurde
lastIndex falls "g" gesetzt ist, die Position des Start der nächsten Suche
source der reguläre Ausdruck selbst

Beispiel 6.1-7

test

Die Methode test() prüft, ob das Muster im String vorkommt; in diesem Fall wird true zurückgeliefert ansonsten false.

Beispiel 6.1-8

Klassen String und RegExp im Zusammenspiel

Bei der Betrachtung der Klasse Sting sind Methoden besprochen worden, mit denen z.B. Such- und Ersetzoperationen darstellbar waren. Folgende Methoden von String sind auch im Zusammenspiel mit regulären Ausdrücken nutzbar:

match(reg)

Wenn str ein String ist und reg ein regulärer Ausdruck:

var str = new String()
var reg = new RegExp();

dann gilt: str.match(reg) == reg.exec(str)

serach(reg)

Wenn str ein String ist und reg ein regulärer Ausdruck:

var str = new String()
var reg = new RegExp();

dann gilt: str.search(reg) == reg.test(str)

replace(regexp, replaceStr)

Mit der Methode replace() der Klasse String kann man nicht nur einen Text in durch einen anderen ersetzen, man kann auch reguläre Ausdrücke angeben, um Stellen im String, die ersetzt werden sollen zu finden.

Das folgende Beispiel ersetzt alle Auftreten von /a+b/ durch xyz.

Beispiel 6.1-9

Im zweiten Argument von replace kann man mit $1, $2, ... auf die Teilstrings, die mit Klammern spezifiziert wurden zugreifen.

So werden im folgenden Beispiel die ersten drei Worte in der Ausgabe in der Reihenfolge vertaucht.

Beispiel 6.1-10

Übung 6.2

Verdeutlichen Sie sich das Zusammenwirken der Methoden von String() und RegExp() an Beispielprogrammen.