
perl
Regular expressions kennen wir schon von grep. Jene in Perl eingebauten
sind noch etwas leistungsfähiger als die von grep. Regular expressions
benutzen wir in Perl vorallem auf 2 Arten:
s/x/u/ ;
s/suchmuster/ersetzmuster/ ersetzte das Suchmuster durch das
Ersetzmuster. Im obigen Fall macht es einem ein x für ein u vor.
allerdings nur eines. Will man dass alle x im string durch ein u ersetzte
werden macht man ein g dahinter (für global) dahinter:
s/x/u/g ;
Der string den der s/// Operator ersetzt ist $_. Will man auf einem
anderen string arbeiten so gibt man (wie schon bei tr/// gelernt) das mit
dem =~ an:
$text = "felerteufel";
$text =~ s/feler/fehler/ ;
Im Suchmuster kann man jetzt ähnlich wie bei grep regular expressions
verwenden:
$name=~ s/^[0-9]+/bla/ ;
Obiges ersetzt eine Ziffernfolge am Anfang eines Wortes (das ^ Zeichen
matched wie auch bei grep auf den Anfang der Zeichenkette, der Ausdruck
[0-9] matched auf eine Ziffer (könnte man auch als d schreiben) und das
+ besagt das ganze mindestens einmal oder öfter vorkommen muss. Der
ausdruck matched also auf alle Ziffern am Anfang einer Zeichenkette und
ersetzt sie durch das Wort "bla".
Neben dem s/// operator gibt es noch den m// operator oder einfach nur //
geschrieben. Der macht keine Ersetzungen sondern prüft nur ob ein string
matched oder nicht.. z.b:
#!/usr/bin/perl -w
while() {
if ( /([0-9.]+)/ ) {
print "ich habe eine Zahl $1 gefunden n";
}
}
Obige Schleife liest von STDIN das // durchsucht den string $_ ob dort
eine Ziffernfolge (eventüll mit Punkt ) ist. Wenn ja wird ein print
aufgerufen. in der Variablen $1 ist nach der match Operation der string
der im ersten () gefunden wurde.
if (/^geburtsdatum: (dddd)-(dd)-(dd)/i ) {
$jahr = $1;
$monat = $2;
$tag = $3;
}
Obige Zeile würde also auf Zeilen matchen die mit "geburtstdatum: "
beginnen, an den richtigen Stellen die - haben und die Teile aus den 3
Klammern in Variablen $1 $2 und $3 speichern. Das i am Ende des
Suchmusters sagt dass Gross- und Kleinschreibung ignoriert werden sollen.
Andere wichtige solcher "modifier" für m// und s/// Operationen:
i ... case insensitiv. Gross/Kleinschreibung ignorieren.
e ... der rechte Teil eines s/// Ausdrucks wird als Perl expresson
ausgewertet.
g ... global. alle Vorkommnisse des Suchstrings einer s/// Operation
werden ersetzt.
s/(bla|bli|blo)+/alles blabla/g;
Würde alle Vorkomnisse von der Ketten bla bli blo oder wenn diese
hintereinander öfter vorkommen durch "alles blabla" ersetzen. Also z.b
auch die Zeichenkette: blibliblobla. das | trennt gleichwertige
Alternativen, die () gruppieren dies und das + sagt dann das beliebig
viele aber mindestens eins davon vorkommen musst damit das Suchmuster
passt.
Nochmal zur Wiederhohlung die Bedeutung der Zeichen in der regular
expression:
zum "escapen" des nachfolgenden zeichen um ihm die
sonderbedeutung zu nehmen.
^ matched auf ein zeilenanfang
. jedes zeichen
$ matched zeilenende
| zum trennen von alternativen
() zum gruppieren
[] zum aufzählen von zeichen
dann haben wir die zeichen die festlegen wie oft ein zeichen oder ein
ausdruck vorkommen muss:
* 0 oder mehrmals
+ mindestens 1 mal
? einmal oder 0 male
{n} genau n mal
{n,} mindestens n mal oder mehr
{n,m} mindestens n mal aber maximal m mal.
damit man nicht immer lange [0-9a-z] und ähnliches ausdrücke schreiben
muss gibt es folgende abkürzungen:
w "wortzeichen" (alphanumerisch und _)
W kein wortzeichen
s whitespace (zwischenraum, tab ..)
S kein whitespace
d eine ziffer (digti)
D keine ziffer
praktisch sind auch:
b eine wortgrenze (also ein whitspace oder überhaupt stringanfang)
B keine wortgrenze
zum Abschluss ein interessantes script:
#!/usr/bin/perl -w
while() {
chomp;
while ( s/ b([a-z]{3,}) b(.*)$/$2/i ) {
print "gefunden $1 n";
}
}
obiges script sucht Wörter die nur aus (mindestens 3) Buchstaben
bestehen: b([a-z]{3,}) b
das gefunden Wort (erste Klammer) ist danach in $1 verfügbar. der string
$_ wird durch $2 ersetzt (also den rest der zeile). beim nächsten
Durchlauf der while Schleife wird jetzt die Suche auf den verbleibenden
Teil in $_ angewendet.... und so weiter.
die Schleife gibt also nacheinander alle Wörter mit 3 Buchstaben aus.
und noch ein kleiner Hinweis: man kann statt des / Trennzeichens auch
andere Zeichen benutzen.
s!x!u!g;
oder
s=x=u=g;
würde also ebenfalls ein x durch ein u ersetzten.. sollte man aber nicht
verwenden ausser man hat ein Suchmuster mit vielen / drinnen die man sonst
alle mit escapen müsste... z.B.:
s!/usr/bin/perl/!/usr/local/bin/perl!g
würde alle Vorkommnisse des strings /usr/bin/perl durch
/usr/local/bin/perl ersetzten.
EXERCISES:
* schreibe ein script das in allen Texten grosse Anfangsbuchstaben eines
Wortes durch kleine ersetzt (jedoch nur in Wörtern). Einzelne Buchstaben[B]
oder Wörter die GANZ grossgeschrieben sind, sollen bleiben wie sie
waren.
* schreibe ein script das die Ausgabezeilen eines Programms wie ps oder
who oder w oder finger oder last mit einer regular expression in
einzelne Felder zerteilt.
REFERENCES:
man perlre
man perlop
|