Inhaltsverzeichnis

REGEX (REGular EXpression => Regulärer Ausdruck)

Die "Basic REGEX" sind recht einfach, allerdings fehlen ihnen einige wichtige Funktionen. Deshalb wurden die REGEX zu den "Extended REGEX" erweitert. Allerdings haben viele Softwarehersteller ihre eigenen erweiterten REGEX-Versionen veröffentlicht, bevor die "Extended REGEX" veröffentlicht wurden. Und so kam es, dass es zur Zeit viele verschiedene erweiterten REGEX-Versionen gibt, die bekannteste ist die "Perl-REGEX"-Version, die meiner Meinung nach auch recht gut gelungen ist.

> echo -e "76556\n765567\n65567\n 65567\n 6556"
76556
765567
65567
 65567
 6556

Grep

Reguläre Ausdrücke mit MySQL

basic regular expressions (BRE)

Das ist die grundlegende Version der POSIX-REGEX.

Understanding Basic Regular Expression (BRE) Syntax

Diese REGEX wird u.a. von "grep" bzw. "grep -G", "vi", "sed", "nl" und "more" unterstützt.

Die BRE kennen keinen Platzhalter für ein Tabulatorzeichen, stattdessen werden hier Leerzeichen erkannt!

genau eine Ziffer:

[0-9]

genau ein Zeichen, das keine Ziffer ist:

[^0-9]

Zeilenanfang:

^

Zeilenende:

$

genau ein beliebiges Zeichen:

.

ein oder mehrere beliebige Zeichen:

.+

kein, ein oder mehrere beliebige Zeichen:

.*

genau ein Punkt:

[.]

mindestens ein Punkt:

[.]+

ein oder kein Punkt:

[.]*

genau ein Leerzeichen:

[ ]

mindestens ein Leerzeichen:

[ ]+

ein oder kein Leerzeichen:

[ ]*

genau einmal irgendein Zeichen, nur kein "/":

[^/]

mindestens einmal irgendein Zeichen, nur kein "/":

[^/]+

ein oder keinmal irgendein Zeichen, nur kein "/":

[^/]*

m-fache Wiederholung von "x":

[x]\{m\}

m..n-fache Wiederholung von "x":

[x]\{m,n\}

m..?-fache Wiederholung von "x":

[x]\{m,\}

wenn nur die Zahl 6556, mit einer zusätzlichen Ziffer auf der rechten Seite und auf der linken Seite keinesfalls eine Ziffer stehen soll, ausgegeben werden soll:

> echo -e "76556\n765567\n65567\n 65567\n 6556" | grep '[^0-9]6556[0-9]'
 65567

Perl regular expressions (PCRE)

Das ist die von Perl erweiterte REGEX-Version, meiner Meinung nach, die beste!

Diese REGEX wird u.a. von "grep -P" unterstützt.

In manchen Anwendungsprogrammen, die mit regulären Ausdrücke umgehen, lässt sich die "Gier" (engl. greed) regeln, mit der Zeichen von einem Wiederholungsoperator, also einem Stern oder einem Pluszeichen, "verschlungen" werden. Und zwar arbeiten diese Operatoren normalerweise mit maximaler Gier, können aber gezähmt werden, indem man ihnen ein Fragezeichen anhängt.

Beispiel zur "Gier": als Zeichenkette wird "Hello World" verwendet

l.+o    ->    llo Wo
l.+?o   ->    llo
l.*o    ->    llo Wo
l.*?o   ->    llo

kein oder ein beliebiges Zeichen:

.?

genau ein Buchstabe oder eine Ziffer:

[0-9A-Za-z]

genau ein Buchstabe:

[a-zA-Z]

genau ein kleiner Buchstabe:

[a-z]

genau ein großer Buchstabe:

[A-Z]

genau eine Ziffer:

[0-9]
[\d]

genau ein Zeichen, das keine Ziffer ist:

[^0-9]
[^\d]
[\D]

genau ein Punkt, Komma oder Semikolon:

[.,;]

genau ein Leerzeichen oder Tabulatorzeichen:

[ \t]

genau ein Leerzeichen:

[ ]

ein Tabulatorzeichen:

\t

ein Zeilenumbruch im Unix-Format:

\n

ein Wagenrücklauf (^M) ⇒ ein Zeilenumbruch im Mac-Format:

\r

ein Zeilenumbruch im Windows-Format:

[\r\n]

logische Verknüpfung "oder":

|

Gruppierung:

(...)

ein Piepston:

\a

ein Seitenvorschub:

\f

ein vertikaler Tabulator:

\v

Wortanfang bzw. Wortende:

\b

alles, nur kein Wortanfang bzw. Wortende:

\B

ein Buchstabe, eine Ziffer oder der Unterstrich:

\w

ein Zeichen, das weder Buchstabe noch Ziffer oder Unterstrich ist:

[\W]
[^\w]

ein Leerzeichen und die Klasse der Steuerzeichen:

[\s]
[\f\n\r\t\v]

ein Zeichen, das kein Whitespace ist:

[\S]
[^\s]

wenn nur die Zahl 6556, mit einer zusätzlichen Ziffer auf der rechten Seite und auf der linken Seite keinesfalls eine Ziffer stehen soll, ausgegeben werden soll:

> echo -e "76556\n765567\n65567\n 65567\n 6556" | grep -P '[\D]6556[\d]'
 65567

extended regular expressions (ERE)

Das ist die erweiterte Version der POSIX-REGEX.

Diese REGEX wird u.a. von "egrep" bzw. "grep -E", "awk" und "Perl" unterstützt.

Die BRE kennen keinen Platzhalter für ein Tabulatorzeichen, stattdessen werden hier Leerzeichen erkannt!

genau ein Buchstabe oder eine Ziffer:

[[:alnum:]]

genau ein Buchstabe:

[[:alpha:]]

genau ein kleiner Buchstabe:

[[:lower:]]

genau ein großer Buchstabe:

[[:upper:]]

genau eine Ziffer:

[[:digit:]]

genau ein Zeichen, das keine Ziffer ist:

[^[:digit:]]

genau ein Hexadezimalziffer:

[[:xdigit:]]

genau ein sichtbares Zeichen:

[[:graph:]]

genau ein druckbares Zeichen:

[[:print:]]

genau ein Punkt, Komma oder Semikolon:

[[:punct:]]

genau ein horizontaler und vertikaler Tabulator, Zeilen- und Seitenvorschub, Wagenrücklauf oder Leerzeichen (Whitespace)

[[:space:]]

genau ein Leerzeichen oder Tabulatorzeichen:

[[:blank:]]

genau ein Steuerzeichen:

[[:cntrl:]]

m-fache Wiederholung von "x":

[x]{m} 	

m..n-fache Wiederholung von "x":

[x]{m,n} 	

m..?-fache Wiederholung von "x":

[x]{m,} 	

wenn nur die Zahl 6556, mit einer zusätzlichen Ziffer auf der rechten Seite und auf der linken Seite keinesfalls eine Ziffer stehen soll, ausgegeben werden soll:

> echo -e "76556\n765567\n65567\n 65567\n 6556" | grep -E '[^[:digit:]]6556[[:digit:]]'
 65567

sed

Leider verwendet sed noch eine andere REGEX-Form, hier ein paar Besonderheiten:

genau ein beliebiges Zeichen:

.

mindestens ein beliebiges Zeichen:

.\+

ein oder kein beliebiges Zeichen:

.*

genau ein Punkt:

[.]

mindestens ein Punkt:

[.]\+

ein oder kein Punkt:

[.]*

genau ein Leerzeichen oder Tabulator (white space):

[ \t]

mindestens ein Leerzeichen oder Tabulator (white space):

[ \t]\+

ein oder kein Leerzeichen oder Tabulator (white space):

[ \t]*

kein Leerzeichen oder Tabulator (white space) am Zeilenanfang:

^\s\+

kein "/" am Zeilenanfang:

^[^/]\+

alles, außer Bindestrich, Unterstrich, Punkt, kleine Buchstaben, große Buchstaben, Zahlen und das Plus:

[^-+_.a-zA-Z0-9]

Hierbei ist zu beachten, dass der Bindestrich als erstes und das Plus als zweites Zeichen angegeben werden! Wird das Plus als letztes angegeben, dann muss es maskiert werden. Der Bindestrich wird von SED als Parameter interpretiert, wenn er nicht als erstes aufgeführt wird.

zum Beispiel kann man so Sonderzeichen aus Dateinamen gegen einen Unterstrich austauschen:

> echo 'Unglaublich! Wenn das passieren würde, bestünde kein Funken Hoffnung mehr_-+ .#zukrassalter.txt' | sed 's/[^-+_.a-zA-Z0-9]/_/g'
Unglaublich__Wenn_das_passieren_wÃ_rde__bestÃ_nde_kein_Funken_Hoffnung mehr_-+_._zukrassalter.txt

Bitte beachtet, dass das "Ã auch ein gültiger Buchstabe aus dem lateinischen Schriftsystem ist und somit von diesem RegEx nicht ausgetauscht wird! Diese "tolle" Zeichenverunstaltung ist dadurch entstanden, dass ein Umlaut aus einem 16-Bit-Zeichensatz als zwei 8-Bit-Zeichen angezeigt wurde.

16-Bit-Zeichensätze sind im internationalen Standard Unicode festgelegt. Unicode enthälten u.a. die Kodierungen UTF-8, die u.a. in Linux, für E-Mail und für WWW verwendet werden sowie die Kodierungen UTF-16, die bei Windows, Mac OS X, Java und .NET verwendet werden.

8-Bit-Zeichensätze sind im internationalen Standard ASCII festgelegt und enthalten die Kodierungen der ISO 8859-Familie. Diese werden mehr und mehr durch Unicode-Zeichensätze abgelöst, werden aber in älteren Systemen (z.B. DOS und älteren Linux-Distributionen) weiterhin verwendet.

Perl Compatible Regular Expressions (PCRE)

hier ein Beispiel für ein Match:

kein Match

# perl -0ne 'print "$ARGV\n" if m/Nameserver/' /etc/resolv.conf

ein Match

# perl -0ne 'print "$ARGV\n" if m/nameserver/' /etc/resolv.conf
/etc/resolv.conf

hier ein Beispiel für ein UND-verknüpften Match:

kein Match

# perl -0ne 'print "$ARGV\n" if m/nameserver/ && m/10.10.2.20/' /etc/resolv.conf

ein Match

# perl -0ne 'print "$ARGV\n" if m/nameserver/ && m/10.10.2.10/' /etc/resolv.conf

/etc/resolv.conf

In Perl werden reguläre Ausdrücke auf mannigfache Weise benutzt. Die einfachste Möglichkeit ist, zu prüfen, ob der Text in einer bestimmten Variablen auf einen regulären Ausdruck paßt. Das folgende Programmstück prüft den String in der Variable $reply und gibt aus, ob darin nur Ziffern vorkommen:

#!/usr/local/bin/perl -w

$var = "0123456789";

if ( $var =~ m/^[0-9]+$/ )
{
        print "$var sind alles nur Ziffern\n";
} else
{
        print "$var sind nicht nur Ziffern\n";
}

Soll nicht nur der erste Treffer modifiziert werden, dann muss am Ende der REGEX ein "g" für global angehängt werden: "m/^[0-9]+$/" wird zu "m/^[0-9]+$/g"

Wenn die Regex wahr ist, dann wird der Teil des Strings in $var, der auf den regulären Ausdruck gepaßt hat, durch Ersatz ersetzt.

#!/usr/local/bin/perl -w

$var = "Jeff";

if ( $var =~ s/Jeff/Jeffrey/ )
{
        print "$var wurde ersätzt\n";
} else
{
        print "$var wurde nicht ersätzt\n";
}

Soll nicht zwischen Groß- und Kleinschreibung unterschieden werden, dann muss man am Ende der REGEX ein "i" hängen: "s/Jeff/Jeffrey/" wird zu "s/Jeff/Jeffrey/i"

Parameter bzw. Argumente übergeben

Will man auf der Kommandozeile Parameter übergeben, dann wird das erste im Perl-Script z.B. mit $var = "$ARGV[0]"; in der Variable $var abgelegt.

Oniguruma regular expressions

Bisher war PCRE die am weitesten verbreitete RegEx-Variante, mittlerweile gewinnt aber eine neue Version immer mehr an Popularität: Oniguruma

Oniguruma ist ist eine RegEx-Bibliothek, die unter der BSD-Lizenz steht, sie unterstützt ein sehr großes Spektrum an Zeichensätzen, darunter auch UTF-8.

Sie wird in der Interpretersprache Ruby seit der Version 1.9 eingesetzt und in der Interpretersprache PHP5. Seit der Version 7.7 verwendet sogar PCRE ein Oniguruma-Konstrukt für Subroutinen.

Es wird ebenso in Produkten wie Tera Term, TextMate und SubEthaEdit eingesetzt.

problematische Sonderfälle, die mir aufgefallen sind

Es bestand das Problem, dass in einem Skript überprüft werden muss, ob eine Zeichenkette numerisch ist oder ggf. Buchstaben enthält.

Leider funktioniert mit "test" ("[") das nicht direkt (siehe "man test"). Also habe ich gedacht, eine negierende RegEx könnte helfen. Wenn also nur Zeichen durchgelassen werden, die nicht nicht-numerisch sind.

Als Testobjekte sollen diese Zeichenketten dienen:

  1. 123
  2. ABC
  3. Def
  4. ghi
  5. 1a
  6. a1

hiervon darf nur die erste (123) durchgehen.

mit Pearl-RegEx würde ich das so formulieren

> echo -e "123\nABC\nDef\nghi\n1a\na1" | grep -P ''[^a-zA-Z]''
123
1a
a1

oder mit extended regular expressions so:

> echo -e "123\nABC\nDef\nghi\n1a\na1" | grep -E '[^[:alpha:]]'
123
1a
a1

Leider funktioniert keine von beiden richtig! :-(

nur diese RegEx funktioniert richtig (Quelle: Post von riffraff im Forum von ubuntuusers.de):

> for A in 123 ABC Def ghi 1a a1 ; do if [[ "${A}" == "?(+|-)+([0-9])" ]] ; then echo "${A}" ; fi ; done
123