ABSTRACT: perl: einfache regular expressions werden erklaert AUDIENCE: perl beginners SYSTEM: any unix SECTION: perl AUTHOR: mond COPYRIGHT: GNU Free Documentation Licence http://www.gnu.org/licenses/fdl.txt regular expressions kennen wir schon von grep. die in perl eingebauten sind noch etwas leistungsfaehiger als die von grep. regular expressions benutzen wir in perl vorallem auf 2 arten: s/x/u/ ; der s/suchmuster/ersetzmuster/ ersetzte das suchmuster durch das ersetzmuster. im obigen fall macht es einem ein x fuer ein u vor. allerdings nur eines. will man dass alle x im string durch ein u ersetzte werden macht man ein g dahinter (fuer 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 aehnlich 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 (koennte man auch als \d schreiben) und das + besagt das ganze mindestens einmal oder oefter vorkommen muss. der ausdruck matched also auf alle ziffern am anfang einer zeichenkette und ersettz sie durch das wort "bla". neben dem s/// operator gibt es noch den m// operator oder einfach nur // geschrieben. der macht keine ersetzungen sondern prueft 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 (eventuell 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: (\d\d\d\d)\-(\d\d)\-(\d\d)/i ) { $jahr = $1; $monat = $2; $tag = $3; } obige zeile wuerde 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" fuer 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 ersettz. s/(bla|bli|blo)+/alles blabla/g; wuerde alle vorkomnisse von der ketten bla bli blo oder wenn diese hintereinander oefter 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 aufzaehlen 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 aehnliches ausdruecke schreiben muss gibt es folgende abkuerzungen: \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 ueberhaupt 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 woerter die nur aus (mindestens 3) buchstaben bestehen: \b([a-z]{3,})\b das gefunden wort (erste klammer) ist danach in $1 verfuegbar. der string $_ wird durch $2 ersetzt (also den rest der zeile). beim naechsten durchlauf der while schleife wird jetzt die suche auf den verbleibenden teil in $_ angewendet.... und so weiter. die schleife gibt also nacheinander alle woerter mit 3 buchstaben aus. und noch ein kleiner hinweis: man kann statt des / trennzeichens auch ander zeichen benutzen. s!x!u!g; oder s=x=u=g; wuerde 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 muesste... z.b.: s!/usr/bin/perl/!/usr/local/bin/perl!g wuerde 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 aber nur in woerter. einzelen buchstaben[B oder woerter 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. * schreibe ein script das ein textfile nach preisangaben in EUR (also nach ausdruecken wie EUR 34.80 EUR oder EUR 234) durchsucht und den EUR preis hinter die zahl in schilling schreibt: also etwa so: aus d der preis ist EUR 100 wird: der preis ist EUR 100 (ATS 1376.03). (beachtet es koennen mehr als ein EUR preis pro zeile vorkommen). hilfestellung: um eine flieskommazahl auf 2 stellen gerundet auszugeben verwendet man z.b.: sprintf("%0.2f",$preisinats) REFERENCES: man perlre man perlop