Suchmuster, Pattern Matching Ein oder mehrere Einzelzeichen in interner Variablen $_suchen: /e/ #liefert wahr, wenn $_ ein 'e' enthält. /aus/ #liefert wahr, wenn $_ 'aus' enthält. while <STDIN> { if (/e/) { print "e ist enthalten in $_ \n"; last; Alternative Muster-Begrenzungszeichen, wenn ein 'm' am Anfang steht: /e/ m(e) m<e> m{e m#e# m:e: #Standard: slashes oder: In Perl gibt es neben index eine weitere Möglichkeit, eine Zeichenkette bzw. eine Variable nach einem Ausdruck zu durchsuchen. Während index die Position eines Zeichen zurückgibt, an der es gefunden wurde, liefert ein Mustervergleich erst einmal nur wahr oder falsch zurück. Ein Mustervergleich wird einfach mit einem Ausdruck in Slashes geschrieben, wie wir in der split- Funktion bereits gesehen haben. Wenn also zum Beispiel nach einem Buchstaben 'e' in einer Zeichenkette gesucht wird, schreibt man einfach /e/ als Suchmuster. Statt den Slashes kann man auch andere Begrenzungszeichen verwenden. Dann muss allerdings ein kleines m vor dem Muster stehen. Als Begrenzungszeichen können dann Doppelpunkte, runde, spitze oder geschweifte Klammern oder Rautezeichen verwendet werden. 97 97
Suchmuster, Matching-Operator Ein oder mehrere Einzelzeichen mit Matching-Operator suchen: $string =~ /e/ #liefert wahr, wenn $string ein 'e' enthält. $string =~ /aus/ #liefert wahr, wenn $string 'aus' enthält. $text = "Heute ist Mittwoch!"; if ($text =~ /ute/) { print "ute ist im Text enthalten\n"; Ein oder mehrere Einzelzeichen mit Matching-Operator ausschließen: $string!~ /e/ #liefert wahr, wenn $string kein 'e' enthält. $string!~ /aus/ #liefert wahr, wenn $string 'aus' nicht enthält. $text = "Heute ist Mittwoch!"; if ($text!~ /frei/) { print "frei ist im Text nicht enthalten\n"; 98 Allerdings sucht dieses reguläre Muster nur in der Variablen $_. Um andere Variablen zu durchsuchen muss der Matching-Operator =~ verwendet werden. Auch hier liefert der Mustervergleich wahr, wenn der Ausdruck in der Varablen vorkommt. Umgekehrt liefert der Matching-Operator!~ (also die Negation) wahr zurück, wenn der Ausdruck nicht in der Variablen vorkommt. Reservierte Metazeichen in einem regulären Ausdruck, d.h. Zeichen die nicht verwendet werden dürfen (oder durch einen vorangestellten Backslash gekennzeichnet werden) sind: + -?. * ^ $ ( ) [ ] { \ 98
Suchmuster, Zeichenklasse in eckigen Klammern Eine Zeichenklasse suchen, d.h. mindestens einen Treffer aus einer Gruppe von Zeichen: /[aeiou]/ #liefert wahr, wenn $_ einen kleinen Vokal enthält. /[aeiouaeiou]/ #liefert wahr, wenn $_ einen beliebigen Vokal enthält. $text = "Heute ist Mittwoch!"; if ($text =~ /[aeiou]/) { print "Im Text sind Vokale enthalten\n"; Einen Zeichenklasse-Bereich suchen: /[a-d]/ #liefert wahr, wenn $_ a, b, c oder d enthält. /[0-9]/ #liefert wahr, wenn $_ eine beliebige Ziffer enthält. /[^0-9]/ #liefert wahr, wenn $_ keine Ziffer enthält. $text = "heute ist mittwoch, der 17.06.2009."; if ($text =~ /[^A-Z]/) {print "Im Text sind Grossbuchstaben nicht enthalten\n" if ($text =~ /[0-9]/) {print "Im Text sind Ziffern enthalten\n" 99 Mit eckigen Klammern wird eine ganze Gruppe von Zeichen definiert, von denen mindestens eines vorkommen muss. Man nennt diese Gruppe Zeichenklasse. Sie kann auch aus einem Bereich bestehen, wenn das Minuszeichen dazwischen steht. Also [a-f] erkennt einen beliebigen Kleinbuchstaben zwischen a und f. Der Ausdruck [a-fa-f] erkennt einen beliebigen Groß- oder Kleinbuchstaben zwischen a und f. Das Minuszeichen selbst muss dann mit Backslash geschrieben werden: [0-9\-] erkennt Ziffern 0 bis 9 und das Minuszeichen. Steht gleich links hinter der eckigen Klammer ein Caret-Zeichen ^, dreht dieses den Sinn um. Also [^0-9] darf keine Ziffer finden! 99
Suchmuster, Vordefinierte Zeichenklassen Kurzformen für häufig benötigte Zeichenklassen: Konstrukt Bedeutung Klasse Negiertes Konstrukt Bedeutung Klasse \d Ziffer 0-9 [0-9] \D keine Ziffer [^0-9] \w Wortzeichen [a-za-z0-9_] \W kein Wortzeichen [^a-za-z0-9_] \s Whitespace [ \r\t\n\f] \S kein Whitespace [^ \r\t\n\f] $text = "17.06.2009."; if ($text =~ /[0-9]/) {print "Im Text sind Ziffern enthalten\n" if ($text =~ /\d/) {print "Im Text sind Ziffern enthalten\n" #identisch! Für mehrere gleiche Zeichen kann das Konstrukt wiederholt werden (das Konstrukt steht für jeweils eine Zeichenstelle). Für beliebig viele Wiederholungen kann ein Stern * benutzt werden: if ($text =~ /\d\d\.\d\d\.\d*/) {print "Im Text ist ein Datum enthalten\n" if ($text =~ /\d\d.\d\d.\d*/) {print "Im Text ist ein Datum enthalten\n" 100 Allerdings ist es unpraktisch, wenn man zum Beispiel einen Zahlenausdruck sucht und dann für jede Ziffer eine komplette Zeichenklasse angeben muss. Deshalb hat man die wichtigsten Ausdrücke in kürzeren Konstrukten zusammengefasst. Diese Konstrukte beginnen (leider) auch mit einem Backslash. So steht dann \d für eine beliebige Ziffer im Text und \w sogar für ein beliebiges Textzeichen. Alles was keine Wortzeichen (Großbuchstabe: \W) sind, müssen dann Steuerzeichen und Rechenzeichen sein. Diese Konstrukte lassen sich dann beliebig kombinieren, um eine bestimmte Textformatierung zu suchen. Übung: Schreiben Sie ein Programm, das eine beliebige Hexadezimalzahl einliest. Anschließend prüfen Sie, ob es ein Hexdezimalzahl war. Falls nicht, wiederholt sich die Eingabe. Eine gültige Hexdezimalzahl wird dann nach dem Hornerschema in eine Dezimalzahl umgewandelt. Lösung: 100
Suchmuster, Muster gruppieren einzelne beliebige Zeichen: /a. / erkennt alle Kombinationen aus zwei Zeichen, die mit a beginnen. Multiplikatoren (Quantifizierer): Meta * +? {n,m {n, {n Bedeutung Kein oder mehrere vorausstehende Zeichen Ein oder mehrere vorausstehende Zeichen Kein oder ein vorausstehendes Zeichen mindestens n und maximal m vorausst. Zeichen mindestens n oder viele vorausst. Zeichen genau n vorausstehende Zeichen Beispiele: / */ Leerz. in "wert 5" /\d+/ /hn?/ /_{1,7/ /s{2,/ /t{2/ eine o. viele Ziffern Huhn, Kuh, Kahn hier drin Wasser, Psssst Matte Weitere Beispiele: /fus+ba?l{2/ fussball, fusbll, fusssball etc. /a.{4w/ aber was (4 beliebige Zeichen zwischen a und w) /\d{2,4/ zwei- bis vierstellige Zahl (Jahreszahl) 101 Meist sucht man nicht nur ganz einfache Zeichen sondern relativ komplizierte Ausdrücke. Wenn Sie zum Beispiel Maier finden wollen, aber auch Meier und Mayer und Meyer, dann brauchen Sie entsprechende Platzhalter. Diese Metazeichen können Sie beliebig gruppieren und anordnen. Natürlich dürfen dabei auch Klammern verwendet werden. Dabei werden allerdings automatisch Speichervorgänge ausgelöst. Das Ergebnis jedes Klammerausdrucks wird in einer Variablen gespeichert: äusserer Klammerausdruck in $1, innerer Ausdruck in $2, $3, usw. Ohne Klammern steht das Suchergebnis immer in $& zur Verfügung! 101
Suchmuster, Vorrang und Alternativen Es wird nach der einen oder anderen Sequenz gesucht: /Muster1 Muster2/ Beispiele: /abc*/ findet ab, abc, abcc, abccc, abcccc, etc. /(abc)*/ findet "", abc, abcabc, abcabc, etc. /^x y/ findet ein x am Zeilenanfang oder ein y an beliebiger Stelle. /^(x y)/ findet ein x oder ein y am Anfang der Zeile. /a bc d/ findet a oder bc oder d. while (1) { print "Noch irgendwelche Wuensche?\n"; if (<STDIN> =~ /^(j J)/) { #Zeile beginnt mit j oder J #Alternative: if (<STDIN> =~ /^[jj]/) print "Und welcher Wunsch ist das?\n"; <STDIN>; #Eingabe verwerfen print "Tut mir leid, das geht nicht!\n"; else {print "Soso...!\n" 102 Gelegentlich weiß man nicht genau, welcher Textteil zusammen mit dem Suchausdruck steht. Aber statt mit Platzhaltern alles zuzulassen, legt man bestimmte Möglichkeiten fest. Dazu schreibt man nur ein Oder-Zeichen zwischen die verschiedenen Möglichkeiten. Der RegEx- Ausdruck findet dann die eine oder die andere Variante. Übung: Schreiben Sie ein Programm, das Sie mit einer Benutzerfunktion zur Eingabe eines Datei-namens auffordert. Die Funktion prüft, ob es die Datei gibt. Dann öffnet das Programm die Datei und durchsucht sie nach Postleitzahlen. Die Postleitzahlen werden dann sortiert in ein Word- Dokument geschrieben. Lösung: 102
Suchmuster, Substitution Durchsucht einen String nach einem Muster und ersetzt es dann: s/alt-regex/ersatztext/ ersetzt in $_ $var =~ s/alt-regex/ersatztext/ ersetzt in $var Suchoptionen: Option Bedeutung g Ersetzt global, also alle Vorkommen i Ignoriert Groß/Kleinschreibung s Läßt. Zeilenumbrüche erkennen x Ignoriert Whitespaces, erlaubt Kommentare e Evaluiert (berechnet) Ersatztexte s/ä/ae/g s/meier/maier/i s/tren-.ung/trennung/s s/ergebnis/$wert1+$wert2/e Mit dem Substitutionsoperator s können in einem Ausdruck alle gefundenen Ausdrücke durch beliebigen anderen Text ersetzt werden. Selbstverständlich dürfen dazu auch Variablen benutzt werden. Beachten Sie aber dabei, dass bestimmte Teile (eckige Klammern für Indizes bei Arrays) unter Umständen falsch interpretiert werden. Be-nutzen Sie also möglichst einfache Skalare. Normalerweise wird nur der erste gefundene Ausdruck ersetzt. Wenn Sie alle pas-senden Ausdrücke ersetzen wollen, können Sie hinter den letzten Slash eine Option angeben. Hier führt zum Beispiel ein g dazu, dass alle Ausdrücke ersetzt werden. Der skalare Rückgabewert der Substitution ist die Anzahl der Ersetzungen! Übung: Schreiben Sie ein Programm, das eine CSV-Messtabelle für Temperaturen einliest. In der ersten Zeile sind wieder die Feldnamen: Meßzeit und datum, Meßstelle1, Meßstelle2, Meßstelle3. 103 Dann wird eine Textdatei eingelesen, die Platzhalter für die Daten enthält. Die Platzhalter sollen ausgefüllt werden (nur für Meßwert1). Geben Sie dann das Ergebnis auf dem Bildschirm oder in eine Datei aus. Die aktuellen Messergebnisse vom dddddddddd lauten: 1. 11111 aaaaa 2. 22222 bbbbb 3. 33333 ccccc Mehr gibt es morgen. Mit freundlichen Gruessen, Blabla. 103
Suchmuster, Transliteration Ersetzt eine Suchliste mit einer Ersatzliste: tr/suchliste/ersatzliste/ ersetzt in $_ $var =~ tr/suchliste/ersatzliste/ ersetzt in $var Optionen: Option c d s Bedeutung Komplement, also alles was nicht in der Suchliste steht Löscht die gefundenen Zeichen ersetzt aufeinanderfolgende Zeichen nur einmal Beispiele: tr/ab/ba/ #vertauscht alle a und b in $_ tr/a-z/a-z/ #ersetzt alle Klein- mit Großbuchstaben tr/äöü/_/ #ersetzt alle Umlaute durch Unterstrich tr/\n/ / #ersetzt alle Zeilenumbrüche mit Leerzeichen tr/\n//d #löscht alle Zeilenümbrüche tr/a-z /a-z /c #ersetzt alles was nicht Kleinbuchstaben sind 104 Eigentlich ist die Transliteration kein Patternmatching im Sinne regulärer Ausdrücke. Aber sie funktioniert so ähnlich. Jedes Zeichen aus der Suchliste, das im Ausdruck vorkommt, wird durch sein entsprechendes Zeichen aus der Ersatzliste ersetzt. Kommt das zweite Zeichen aus der Suchliste vor, wird es mit dem zweiten Zeichen der Ersatzliste ersetzt. Falls die Ersatzliste kleiner ist als die Suchliste, vervielfältigt Perl die Ersatzliste bis die Anzahl stimmt. Geben Sie keine Ersatzliste an, gibt die Transliteration die Anzahl der Übereinstimmungen zurück, also wie viele Elemente der Suchliste gefunden wurden. 104