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