![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
||||||||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Reguläre AusdrückeEinführung in Perl IIIvon Achim Schmidt |
![]() |
Abbildung 1: demo3-1.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); print "\nSuchtext: "; chop ($such = <STDIN>); if ($eingabe =~ /$such/) { print "Die Kombination '$such' wurde in '$eingabe' gefunden\n\n"; } else { print "'$such' ist in '$eingabe' nicht enthalten !\n\n"; } |
as@thor:/home/as/txt/lnxmag/perl/3 > demo3-1.pl Zeichenkette: Dies ist ein erster Test Suchtext: erster Die Kombination 'erster' wurde in 'Dies ist ein erster Test' gefunden as@thor:/home/as/txt/lnxmag/perl/3 > demo3-1.pl Zeichenkette: Dies ist ein zweiter Test Suchtext: erster 'erster' ist in 'Dies ist ein zweiter Test' nicht enthalten ! as@thor:/home/as/txt/lnxmag/perl/3 > |
Wie arbeitet dieses Programm nun? Der Benutzer wird aufgefordert, eine Zeichenkette einzugeben, welche mit einer zweiten einzugebenen Zeichenkette untersucht werden soll. An Hand der Formulierung der Eingabeaufforderung sieht man nun auch eine weitere der Stärken von Perl. In Perl sind Verschachtelungen an fast allen denkbaren Stellen möglich, was zwar nicht immer zur besseren Lesbarkeit des Quelltextes beiträgt, aber dem Autor beim Programmieren sehr leicht von der Hand geht und jede Menge Tipperei erspart. Die Anweisung
chop ($eingabe = <STDIN>);liest Zeichen von der Standardeingabe ein und legt diese in der Skalarvariablen $eingabe ab, welche gleichzeitig von Ihrem letzen Zeichen ( in diesem Fall das Newline) befreit wird, so daß nach der Abarbeitung dieser Zeile in $eingabe bereits der weiterverarbeitbare Text ohne das störende Newline enthalten ist.
Abbildung 2: demo3-2.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); print "\nSuchtext: "; chop ($such = <STDIN>); print "\n neuer Text: "; chop ($ersetz = <STDIN>); print "\nIhre Eingabe: $eingabe"; $eingabe =~ s/$such/$ersetz/ ; print "\nNach Ersetzung: $eingabe\n\n" ; |
as@thor:/home/as/txt/lnxmag/perl/3 > demo3-2.pl Zeichenkette: Dies ist ein kleiner Versuch Suchtext: Versuch neuer Text: Test Ihre Eingabe: Dies ist ein kleiner Versuch Nach Ersetzung: Dies ist ein kleiner Test as@thor:/home/as/txt/lnxmag/perl/3 > |
Dieses kleine Programm liest nun drei Zeichenketten ein. Eine, in welcher gesucht und verändert werden soll ($eingabe), die zu suchende (zu ändernde) Zeichenkette ($such) und die Zeichenkombination, welche eingesetzt werden soll ($ersetz).
Anschließend wird der eingegebene Text in $eingabe nocheinmal ausgegeben und der reguläre Ausdruck mit Substituionskommando auf sie angwandt. Nach dessen Abarbeitung wird die Variable $eingabe erneut ausgegeben, welche nun jedoch nicht mehr den Originaltext sondern den veränderten Text enthällt.
Abbildung 3: demo3-3.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); if ($eingabe =~ /[0-9]/) { print "Die Eingabezeile enthällt Ziffern !\n\n"; } else { print "Die Eingabezeile enthällt keine Ziffern !\n\n"; } |
Nachdem die Eingabezeile eingelesen und in der Variable $eingabe (ohne Newline) gespeichert wurde wird mittels des regulären Ausdruckes /[0-9]/ überprüft, ob in der Variable $eingabe Ziffern enthalten sind. In Abhängigkeit des Rückgabewertes wird nun der entsprechende Anweisungsblock ausgeführt.
Abbildung 4: demo3-4.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); if ($eingabe =~ /[^0-9]/) { print "Ihre Eingabe ist keine ganze Zahl !\n\n"; } else { print "Die Eingabe ist eine ganze Zahl !\n\n"; } |
Dieses Programm prüft, ob die eingegebene Zeichenkette eine ganze Zahl ist,
also nur die Zeichen von Null bis 9 enthällt. Der reguläre Ausdruck liefert hier ein true sobald andere Zeichen als Ziffernzeichen eingegeben werden und false, falls nur Ziffern in der Eingabe auftreten. Es wird hier also wirklich mit einer negativen Logik gearbeitet, welche innerhalb des regulären Ausdruckes durch das Hütchenzeichen symbolisiert wird.
Die wichtigsten Zeichengruppen liefert Perl auch schon als Kürzel mit, welche in nachfolgender Tabelle aufgelistet sind:
Kürzel gleichbedeutend BedeutungNimmt man anstelle der Kleinbuchstaben die entsprechenden Großbuchstaben, so hat dies die gleiche Wirkung wie ein der gleichbedeutenden Gruppe vorangestelltes Caret Zeichen.
\d [0-9] Ziffern
\w [a-zA-Z0-9_] komplette Woerter (alle Buchstaben, Ziffern und Unterstrich)
\s [ \r\t\n\f] Leerraum (Space,Tab,Carrige Return, Linefeed, Formfeed)
Abbildung 5: demo3-5.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); print "Ihre Eingabe: $eingabe\n\n"; $eingabe =~ s/Sauerstofff?lasche/Luftvorrat/ ; print "Nach der Änderung: $eingabe\n\n"; |
Dieses Beispiel wandelt sowohl die Eingabe Sauerstoffflasche als auch Sauerstofflasche in das Wort Luftvorrat um, jedoch kein anderes Wort, d.h. es wandelt das Wort Sauerstofflasche in Luftvorrat, unabhängig davon, ob es mit zwei oder drei f geschrieben wurde.
Der erste Anker, wäre der Anker \b. Dieser bestimmt, daß ein Teil der Übereinstimmung auf eine Wortgrenze fallen muß, d.h. der reguläre Ausdruck /Test\b/ würde beim Auffinden der Zeichenkette Test wahrliefern, nicht jedoch bei Testdruck. Wird also der Anker \b hinter einen Ausdruck gesetzt, so muß er am Ende eines Wortes innerhalb der zu überprüfenden Zeichenkette stehen.
Der reguläre Ausdruck /test\b/ würde beispielsweise:
teststring | nicht finden, da test nicht am Wortende steht |
test | finden, da es am Wortende (=gesamtes Wort) steht |
Stringtest | finden, da es am Ende der Zeichenkette Stringtest steht |
Steht der Anker hingegen vor dem entsprechenden Ausruck (z.B. /\btest/), so muss es am Anfang eines Wortes innerhalb der zu prüfenden Zeichenkette stehen.
Dementspechend trifft der Ausdruck /\btest\b/ nur auf Zeicheketten zu, welche das Wort test als eigenes Wort (also ohne Zusammensetzungen) enthalten, da auf eine Wortgrenze am Anfang und Ende geprüft wird.
Der Anker \B legt fest, daß an der enstprechenden Stelle im zu testenden String explizit keine Wortgrenze sein darf. Dies bedeutet also, daß der reguläre Ausdruck /Test\B/ true liefert, wenn der zu überprüfende Ausdruck Testdruck ist, jedoch false bei Test oder DruckerTest.
Abbildung 6: demo3-6.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); if ($eingabe =~ /Test|Demo/) { print "In '$eingabe' ist Test oder Demo vorhanden\n\n"; } else { print "In '$eingabe' ist weder Test noch Demo vorhanden !\n\n"; } |
Dieses Programm gibt eine Erfolgsmeldung aus, sobald Ihre Eingabe die Worte Test, Demo oder beide enthält.
Abbildung 7: demo3-7.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); if ($eingabe =~ /(Test|Demo).*\1/) { print "$1 ist in '$eingabe' doppelt vorhanden ! \n\n"; } else { print "Weder Test noch Demo sind doppelt in '$eingabe' vorhanden \n\n"; } |
as@thor:/home/as/txt/lnxmag/perl/3 > demo3-7.pl Zeichenkette: Dies ist ein Test für den Test Test ist in 'Dies ist ein Test für den Test' doppelt vorhanden ! as@thor:/home/as/txt/lnxmag/perl/3 > demo3-7.pl Zeichenkette: Dies ist eine Demo für den Test Weder Test noch Demo sind doppelt in 'Dies ist eine Demo für den Test' vorhanden as@thor:/home/as/txt/lnxmag/perl/3 > |
Was macht dieses kleine Programm nun? Zuest nimmt es eine beliebige Eingabe vom Standardeingabegerät entgegen und kürzt diese um ein \n. In der anschließenden if-&Abfrage ist nun der reguläre Ausdruck
$eingabe =~ /(Test|Demo).*\1/zu finden. Dieser bewirkt nun folgende Überprüfung: Zuerst wird nach Test oder Demo gesucht, welche hier jedoch in Klammern stehen. Diese Klammern sind die Kennzeichnung für die Zwischenspeicherung. Gespeichert wird der erste Wert, welcher auf das Suchmuster zutrifft, hier also das erste Vorkommen von Test oder Demo. Das .* innerhalb des regulären Ausdruckes steht für beliebig viele Zeichen. Der Punkt steht dabei für ein beliebiges Zeichen, welcher durch den Multiplikationsoperator * beliebig oft (auch Null mal) vorkommen darf. Anschließend steht im regulären Ausdruck ein \1 . Dieses \1 ist nun ein Zugriff auf den vorher (ersten) zwischengespeicherten Wert. Der Reguläre Ausdruck prüft also auf Test oder Demo, beliebig viele Zeichendazwischen und ein wiederholtes Vorkommen des ersten gefundenen Wertes aus dem geklammerten Ausduck. Kurz gesagt, er prüft auf das doppelte Vorkommen von Test oder Demo innerhalb der angegebenen Zeichenkette (hier in $eingabe). In der Ausgabe ist nun noch zu beachten, das der doppelt vorhandene Audruck ausgegeben wird, naemlich mittels der Variablen $1, welche von Perl mit dem ersten zwischengespeicherten Wert belegt wird !
Das if Konstrukt wertet die Rückgabe des regulären Ausdruckes aus und gibt eine entsprechende Meldung aus. Dieses kleine Programm ist, so denke ich zumindest, wirklich ein schönes Beispiel für die Leitungsfähigkeit regulärer Ausdrücke, wenn man einmal den Programmieraufwand für eine entsprechnde Funktion ohne Anwendung regulärer Ausdrücke bedenkt.
Sollen mehrer Zeichenmuster zwischengespeichert werden, so ist auch dies möglich, indem einfach mehrere Klammerungen verwendet werden, auf welche dann mit \1, \2, \3, usw. zugegriffen werden kann. Die entsprechenden Werte stehen nach der Abarbeitung automatisch in den entsprechenden Skalarvariablen !
Abbildung 7: Beispiel mit demo3-1.pl |
as@thor:/home/as/txt/lnxmag/perl/3 > demo3-1.pl Zeichenkette: Dies ist die Eingabezeile Suchtext: [fz]eile Die Kombination '[fz]eile' wurde in 'Dies ist die Eingabezeile' gefunden as@thor:/home/as/txt/lnxmag/perl/3 > |
In diesem Beispiel wird also nicht nach dem Text [fz]eile gesucht, der in der Eingabe ja gar nicht vorhanden war, sondern nach zeile oder feile, da der eingegebene Suchtext als Muster behandelt wird. Diese Funktion kann man jedoch unterdrücken, indem man die zu ersetzende Variable mit den Operatoren \Q und \E umgibt.
Unser abgeändertes Programm ist in Abbilidung 8 zu sehen..
Abbildung 8: demo3-8.pl |
#!/usr/bin/perl print "\nZeichenkette: "; chop ($eingabe = <STDIN>); print "\nSuchtext: "; chop ($such = <STDIN>); if ($eingabe =~ /\Q$such\E/) { print "Die Kombination '$such' wurde in '$eingabe' gefunden\n\n"; } else { print "'$such' ist in '$eingabe' nicht enthalten !\n\n"; } |
as@thor:/home/as/txt/lnxmag/perl/3 > demo3-8.pl Zeichenkette: Dies ist die Eingabezeile Suchtext: [fz]eile '[fz]eile' ist in 'Dies ist die Eingabezeile' nicht enthalten ! as@thor:/home/as/txt/lnxmag/perl/3 > |
Der gleiche Progammaufruf würde nun negativ ausgehen, da wirklich nach dem eingegebenen Suchtext gesucht wird und dieser nicht mehr als Muster betrachtet wird (Siehe Abbildung 8).
Ich denke, daß Sie nun von der Leitungsfähigkeit regulärer Ausdrücke überzeugt sein dürften, obwohl ich bei weitem nicht auf all deren Möglichketen eingegangen bin, da dies den Rahmen dieses Artikels um einiges sprengen dürfte. Ich hoffe jedoch eine recht gute Auswahl getroffen zu haben, da diese Anwendungen in Ihrer täglichen Perlerei wohl häufiger zum Einsatz kommen dürften.
Literatur |
Larry Wall & Randal L. Schwartz: Programming Perl, 2nd Edition O'Reilly & Associates, Inc. ISBN 1-56592-6 Randal L. Schwartz: Einführung in PERL O'Reilly International Thomson Verlag ISBN 3-930673-08-8 |
Der Autor |
Achim Schmidt ist staatlich geprüfter Assistent für Automatisierungs- und Computertechnik (HBFS) und beschäftigt sich bereits seit 6 Jahren intensiv mit dem Internet und seinen Diensten. Mit Linux wurde er erstmalig 1992 beim Aufbau eines Mailboxsystemes direkt konfrontiert. Seit 1993 sind bereits einige Publikationen (http://www.saar.de/~as/publications/) von ihm in verschiedenen Medien erschienen . Seit 1995 ist er als Netzwerk- und Systemmanager tätig und beschäftigt sich dabei auch mir der Entwicklung und Realisierung WWW- basierter Onlinesysteme und Internetkopplungen. Zu erreichen ist er unter as@Saar.DE. |
Copyright © 1997 Linux-Magazin Verlag