
Was sind Regular Expressions?
$_ als Default Wert
der Binding Operator
Optionen: i und g
Die mit Regular Expression übereinstimmenden
Textteile abfangen: $1
Angeben wie oft ein Zeichen vorkommen soll: +
und *
+ und * sind im Default greedy
Umstellen auf nicht greedy: ?
Was ist
eigentlich ein Wordelement(\w)?
Kurzschreibweise für irgendeine Zahl: \d
anstatt [0-9]
Präzise angeben, wie oft ein Zeichen vorkommen
soll: {mindestens,höchstens}
Gruppen bilden: [das Zeichen | oder jenes |
oder dieses]
Anker setzen: ^ und $
Den Inhalt der eckigen Klammer negieren: ^
Praktisches Beispiel: Prüfen ob es sich
um eine email Adresse handelt
Praktisches Beispiel: Den Namen eines Bildes
ermitteln
Regular Expressions in Verbindung mit substitution,
split und grep
Praktisches Beispiel:
HTML Tags eliminieren
Praktisches Beispiel:
Links in den image tag einbinden
Praktisches Beispiel:
Mit grep und Regular Expression bestimmte Elemente eines Arrays
finden
Zusammenfassung
| Was
sind Regular Expressions? |
|
Die Regular Expressions gehören
zu den wichtigsten und mächtigsten Funktionen von Perl.
Die Verbreitung von Perl im Internet dürfte auf die Regular
Expressions zurückzuführen sein. Hier hat man es
selten mit mathematischen Problemen zu tun. Meistens geht
es darum, Texte in der einen oder anderen Weise zu manipulieren.
Dabei sind die Regular Expressions ein enorm leistungsfähiges
Tool. Sie sind die abstrakte Formulierung, eines bestimmten
Typs von Text. Geniale Erklärung? Hier ein Beispiel:
Wir haben drei Zeichenketten.
1. Die Affen rasen durch den Wald, der eine macht den anderen
kalt, die ganze Affenbande singt .....
2. Die Affen, die nächsten Verwandten des Menschen, sind
als Babys lange nicht so putzig wie kleine Hunde.
3. Wenn manche Affen deprimiert sind, dann ist das eine deprimierende
Erkenntnis.
Wir haben also einen bestimmten Typ von Text vor uns, der
folgendermaßen strukturiert ist. Zu Beginn kommen ein
paar Buchstaben, dann kommt das Wort Affen, dann wieder eine
ganze Portion Buchstaben. Die Regular Expression dazu ist
also eine Portion Buchstaben, dann das Wort Affen, dann eine
Portion Buchstaben. Solche Elemente findet man oft. Email-Adressen
haben eine bestimmte Struktur, Hyperlinks haben eine bestimmte
Struktur, Html Seiten haben eine bestimmte Struktur etc. etc..
Alles, was irgendwie eine wie auch immer geartete Struktur
hat, lässt sich mit Regular Expressions manipulieren.
Regular Expressions können auch dann noch verwendent
werden, wenn der Text nur schwach strukturiert ist.
Der einfachste Fall einer Regular Expression sieht so aus:
Anwendungen - Beispiele
$banane="Every beat of my heart brings me further apart.";
$_=$banane;
$test=m/heart/;
print $test; Erklärungsbedürftig?
Der Match Operator (m) geht im Default auf die Sondervariable
$_. Die kennen wir schon aus Funktionen
zur Bearbeitung von Arrays. Warum das so ist, versteht
kein Mensch, aber unter Umständen ist dies praktisch,
wenn man etwas mit Regular Expression im Zusammenhang mit
Arrays macht. Die zwei Querbalken / (neudeutsch Slash) sind
die Begrenzungen der Regular Expression. Anstelle des Slashs
kann sonst was stehen, also z.B.:
$banane="Every beat of my heart brings me further apart.";
$_=$banane;
$test=m!heart!;
print $test;
Das funktioniert
genauso gut. Wird die Regular Expression, in diesem konkreten
Fall eine Karikatur einer solchen, gefunden, dann gibt der
Match Operator 1 zurück, was hier der Fall ist. Nach
dem Ausführen des Skriptes steht 1 auf dem Bildschirm.
In den meisten Fällen ist es nicht so praktisch, dass
der Match Operator auf den $_ geht. In der Regel lenkt man
ihn besser um. Das passiert mit dem Binding Operator (~).
$banane="Every beat of my heart brings me further apart.";
$test=$banane=~m!heart!;
print $test;
$test ist jetzt
wieder 1, weil heart in $banane enthalten ist. Meistens will
man aber irgendetwas machen bzw. lassen, wenn die Regular
Expression in dem Ausdruck enthalten ist. Dann ist folgendes
sinnvoll:
$banane="Every beat of my heart brings me further apart.";
if($banane=~m!heart!)
{
print "Das Wort heart ist in der Zeichenkette enthalten";
}
Alles klar?
1 ist das Äquvalent für true. Die if Bedingung wird
ausgeführt, wenn sie true ist. Das ist hier der Fall.
Was ist aber, wenn man wissen will, wie oft ein bestimmtes
Element in einer Zeichenkette enthalten ist. Dies interessiert
brennend in der Bioinformatik, wenn man wissen will, wie oft
eine bestimmte Gensequenz in einer Zeichenkette enthalten
ist. Das sieht dann so aus:
$banane="Ene dene dippe dene dippe dene dalia ebbe bebbe bem bio bio bio puf";
$test=@test=$banane=~m/ene/g;
print $test; @test ist jetzt
ein Array, der genau so viele Elemente hat, wie in der Zeichenkette
ene gefunden wurde. Die Betonung liegt auf ene (Ene zählt
erstmal nicht mit). Das werden wir gleich ändern. Die
Zuweisung im Skalarkontext an $test hat dann die Anzahl der
Elemente. Siehe Funktionen
zur Bearbeitung von Arrays. Soll ene gefunden werden,
unabhängig von Groß-/ Kleinschreibung, dann braucht
man neben dem g wie general, das dafür sorgt, dass nach
dem ersten Treffer nicht gestoppt wird, noch ein i wie indifferent,
das dafür sorgt, dass Groß- und Kleinschreibung
keine Rolle mehr spielt.
$banane="Ene dene dippe dene dippe dene dalia ebbe bebbe bem bio bio bio puf";
$test=@test=$banane=~m/ene/gi;
print $test;
Oben wirft die
Variable $test den wert 3 aus, unten den Wert 4, weil das
erste Ene noch dazugekommen ist.
Manchmal ist es interessant in Erfahrung zu bringen, was vor
oder nach der Zeichenkette kommt, die gefunden worden ist.
Ein Beispiel hierzu unter Suchmaschine in festen
Ordnern. Dies geht in einem einfachen Beispiel so.
|
Die mit Regular Expression übereinstimmenden Textteile
abfangen: $1 |
|
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de';
$banane=~m/@(......)/;
print $1;
Die Punkte
stehen für x-beliebige Zeichen (Buchstaben, Hyroglyphen
(§$%& etc.), Zahlen usw. Wir haben in diesem Beispiel
sechs Punkte(web.de). (In der Praxis ist es komplizierter,
wir kommen darauf gleich zurück, weil wir in der Regel
nicht genau wissen, nach wievielen Zeichen wir suchen). Entscheidend
ist, dass die Punkte in runden Klammern stehen. Was hier steht
wird in der Sondervariablen $1 abgespeichert (bei zwei Klammern
in $2 etc). Wir erhalten also in diesem Fall für $1 den
Wert web.de.
(Nebenbemerkung: In diesem Fall muss die Zeichenkette in einfachen
Anführungsstrichen stehen. Hier werden Variablen nicht
interpretiert. Sonst sucht Perl nach einem Array Namen @web,
den wir aber nicht haben. In einfachen Anführungsstrichen
ist das @ Zeichen ein @ Zeichen und kein Array. Das ist hier
beabsichtigt.
Alternative: Über den Escape Operator das @ Zeichen abklemmen,
also \@.)
Bleiben zwei Probleme:
1. es ist nicht bekannt wie viele Zeichen die Domain hat
2. man will viele Domains nach diesem Schema auslesen.
Fangen wir mit dem ersten Problem an. Die Lösung sieht
so aus:
|
Angeben wie oft ein Zeichen vorkommen soll: + und * |
|
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de';
$banane=~m/@(.+)/;
print $1;
Hier ist
das Ergebnis web.de und zwar völlig unabhängig davon,
wie viele Zeichen die Domain hat. Der Punkt steht hier für
jedes x-beliebige Zeichen und davon mindestens eins oder beliebig
viele(+). Bei the way, würde man statt des + Zeichens
einen * setzen, bedeutet das für das für das unmittelbar
davor stehende Zeichen, dass es beliebig oft oder Null mal
vorkommen muss. Schwierig wird es, wenn es nach der Domain
noch weiter geht, wenn wir also etwas in der Art haben.
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de.
Ich bin der Konfliktstoff. Noch schlimmer wird es bei mehreren Punkten';
$banane=~m/@(.+)/;
print $1; Hier
funktioniert es leider nicht mehr. Das Ergebnis ist jetzt
web.de. Ich bin der
Konfliktstoff. Noch schlimmer wird es bei mehreren Punkten
Dies ist logisch. Jedes x-beliebige Zeichen und davon x-beliebig
viele. Es stellt sich also die Frage, wie man die Regular
Expression so formuliert, dass sie nach web.de anählt.
Man kann erstmal eine Grenze angeben, bis zu der die Regular
Expression laufen soll z.B.:
|
+ und * sind im Default greedy |
|
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de.
Ich bin der Konfliktstoff. Noch schlimmer wird es bei mehreren Punkten';
$banane=~m/@(.+)\./;
print $1;
Das Ergebnis
ist hier ein Anhalten nach dem letzten Punkt web.de.
Ich bin der Konfliktstoff. Der Punkt muss escaped
werden, da er ja selber eine Bedeutung hat (x-beliebiges Zeichen).
Wir sehen also, dass das + wie auch das * Zeichen durchgreift,
bis zu der Stelle, wo das darauffolgende Zeichen zuletzt auftaucht.
Das + Zeichen wie auch das * Zeichen sind also greedy (gierig).
Sie stoppen nicht vor dem nächsten übereinstimmenden
Zeichen, sondern vor dem letzten. In unserem Beispiel ist
das aber nicht das, was wir wollen. Eine ganz entscheidende
Bedeutung erlangt jetzt das Fragezeichen - Beispiel:
|
Umstellen auf nicht greedy: ? |
|
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de.
Ich bin der Konfliktstoff. Noch schlimmer wird es bei mehreren Punkten';
$banane=~m/@(.+?)\./;
print $1;
Dies ist
leider zuviel des Guten. Hier kommt es zu einem Stopp vor
dem ersten Punkt, also nach web..
Wir müssen also die anderen zwei Zeichen dazugeben. Das
sieht dann so aus:
$banane='Zu welcher Domain gehört eigentlich die email Adresse Andres_Ehmann@web.de.
Ich bin der Konfliktstoff. Noch schlimmer wird es bei mehreren Punkten';
$banane=~m/@(.+?\.\w+?)\b/;
print $1;
Allmählich
wird die Sache schwierig, da diese Regular Expression nicht
alle Domains abdeckt. Also step by step. Was steht jetzt in
der Regular Expression? Suche ein @ Zeichen! Nach dem @ Zeichen
soll irgend ein beliebiges Zeichen folgen, davon mindesten
eins (+) oder beliebig viele. Der + Operator soll nicht greedy
sein, das heißt, er soll nicht durchmarschieren bis
zum letzten Punkt, sondern nur bis zum nächsten Punkt.
Danach soll irgendein Wordelement kommen (\w). Von diesen
Elementen wiederum soll es mindesten eines geben oder beliebig
viele. Stoppen soll er vor der nächsten word boundary
(\b). Das Ergebnis ist web.de.
Alles in den runden Klammern wird in der Sondervariablen $1
abgespeichert.
| Was
ist eigentlich ein Wordelement(\w)? |
|
Als Wordelement zählen keine Umlaute kein ß, keine
spanisches n mit tilde, kein französisches s mit ceguille,
kein Punkt, etc.. Um es ganz klar zu machen:
\w ist abcdefghijklmnopqrstuvwxyz (groß und klein) 1234567890
und _ mehr nicht. Dies sei hier deutlich gesagt, weil es manchmal
auch in der Literatur falsch steht.
Für die Ungläubigen unter uns, ein Beispiel. Man
kann damit rumspielen und sich von der Richtigkeit des oben
Gesagten überzeugen.
$banane='testXtest';
$banane=~m/(test\wtest)/;
print $1;
Funktioniert!
X ist ein ein Wordelement. $1 ist testXtest
$banane='test_test';
$banane=~m/(test\wtest)/;
print $1;
_ ist ein ein
Wordelement. $1 ist test_test
$banane='test4test';
$banane=~m/(test\wtest)/;
print $1;
4 ist ein ein
Wordelement. $1 ist test4test
$banane='testätest';
$banane=~m/(test\wtest)/;
print $1;
Funktioniert
nicht! ä ist kein ein Wordelement. $1 ist undef. (auf
dem Schirm leer)
$banane='test.test';
$banane=~m/(test\wtest)/;
print $1;
der Punkt . ist
kein ein Wordelement. $1 ist undef. (auf dem Schirm leer)
Bevor ein Überblick gegeben wird, über
Regular Expressions, noch ein paar Beispiele, damit das Prinzip
klar wird. Nehmen wir mal an, dass man eine Anwendung hat,
bei der der User eine Telefonnummer eingeben kann. Die soll
folgendes Format haben. 030-47301388. Also Vorwahl, dann Bindestrich,
dann Nummer. Buchstaben dürfen also keine vorkommen.
Wie prüft man das mit einer Regular Expression. Die Lösung
sieht so aus:
|
Kurzschreibweise für irgendeine Zahl: \d anstatt
[0-9] |
|
$banane='030-47301388';
$banane=~m/(\d+-\d+)/;
print $1;
Zur Abwechslung
haben wir jetzt \d, wobei \d für Zahlen steht. Wir suchen
also einen Texttyp, der zuerst mal ein paar Zahlen hat (mindesten
eine oder beliebig viele), dann soll ein Bindestrich kommen,
dann wieder eine Portion Zahlen. Bei dieser Variante dürfen
also keine Buchstaben vorkommen. Das können wir verbessern.
Vorwahlen haben in Deutschland mindestens 3 und höchstens
5 Ziffern. Man kann also erzwingen, dass zuerst 3 bis 5 Zahlen
stehen, dann der Bindestrich und dann die eigentliche Nummer.
$banane='030-47301388';
$banane=~m/(\d{3,5}-\d+)/;
print $1;
Man beachte die
geschweiften Klammern ({3,5}). Das bedeutet, das Zeichen \d
(also eine Zahl) muss mindestens 3 mal und darf höchstens
5 mal auftauchen. Obiges Beispiel liefert ein korrektes Ergebnis.
Im folgenden Beispiel tauchen vor dem Bindestrich nur zwei
Zahlen auf. Das heißt ({3,5}) trifft nicht zu.
|
Präzise angeben, wie oft ein Zeichen vorkommen soll:
{mindestens,höchstens} |
|
$banane='03-47301388';
$banane=~m/(\d{3,5}-\d+)/;
print $1;
Jetzt schauen
wir uns im nächsten Beispiel Gruppen an.
|
Gruppen bilden: [das Zeichen | oder jenes | oder dieses] |
|
$banane='ene';
$banane=~m/([ead])/;
print $1;
Ist das ein Treffer
oder nicht? Es ist ein Treffer. Die eckige Klammer ändert
alles. Nicht ead soll gefunden werden, sondern entweder e,
a oder d. In ene ist das e enthalten. Wir erhalten e als Ergebnis.
Die eckigen Klammern begegnen uns gleich wieder.
Im den nächsten drei Beispielen wollen wir erzwingen,
dass die Regular Expression am Anfang der Zeichenkette steht.
$banane='ene dene dippe denne dippe denne dalia ebbe bebbe bem bio bio bio puff';
$banane=~m/(denne)/;
print $1; Funktioniert ist
klar, denne ist enthalten.
$banane='ene dene dippe denne dippe denne dalia ebbe bebbe bem bio bio bio puff';
$banane=~m/^(denne)/;
print $1; Hier wird die
Regular Expression nicht erkannt, weil das ^ Zeichen erzwingt,
dass die Regular Expression am Anfang steht.
$banane='ene dene dippe denne dippe denne dalia ebbe bebbe bem bio bio bio puff';
$banane=~m/^(ene)/;
print $1;
Hier wird die
Regular Expression erkannt, da ene am Anfang steht.
Das Dach ^ innerhalb der eckigen Klammern hat eine ganz andere
Bedeutung hat als außerhalb. Beispiel:
|
Den Inhalt der eckigen Klammer negieren: ^ |
|
$zahlen="12345";
$zahlen=~m/([^\d])/;
print $1;
Hat $1 einen
Wert oder hat es keinen? Es hat keinen, weil das ^ hier den
Inhalt negiert. Gesucht wird also nicht nach Zahlen, sondern
nach dem genauen Gegenteil, das heißt alles, aber keine
Zahl.
$zahlen="ft$§ttt";
$zahlen=~m/([^\d])/;
print $1;
Mit den
eckigen Klammern kann man wie schon erwähnt Gruppen bilden,
z. B. [abc] oder [a-c] oder [$§&] etc. etc.. Einige Gruppen
hatten wir schon. \d ist [1234567890] bzw.in Kurzschreibweise
[0-9] und \w ist [a-zA-Z_1234567890] .
Mit dem ^ erzwingt man, dass die Regular Expression am Anfang
steht, mit dem $ Zeichen, dass sie am Ende steht.
$banane='ene dene dippe denne dippe denne dalia ebbe bebbe bem bio bio bio puff';
$banane=~m/(ene)$/;
print $1;
Hier zeigt $1
nichts, da ene nicht am Ende steht.
$banane='ene dene dippe denne dippe denne dalia ebbe bebbe bem bio bio bio puff';
$banane=~m/(puff)$/;
print $1;
Hier steht puff
steht am Ende. Das heißt $1 ist puff.
Was haben wir gelernt?
Klar ist, was \d und \w, ist, was die eckigen, die geschweiften
und die runden Klammern bedeuten.
Was man mit i und g erreicht. Was der Binding Operator bewirkt.
$1, ^ und $. $_ kennen wir auch. Wir wissen auch, dass es
eine Möglichkeit gibt, alle Zeichenketten rauszufischen,
die im Hinblick auf ihre Struktur mit der Regular Expression
identisch sind.
So ziemlich auf jeder zweiten Website gibt es ein Gästebuch,
einen Newsletter, ein Forum oder ein Kontaktformular. Man
kann mit einer Regular Expression prüfen, ob die Eingabe
der Email-Adresse zumindest syntaktisch richtig ist. Beispiel:
|
Praktisches Beispiel: Prüfen ob es sich um eine email
Adresse handelt |
|
$email='infos@infos24.de';
$test=$email=~m!^\w[\w|\.\-]+@\w[\w\.\-]+\.[a-zA-Z]{2,4}$!;
print $test; Zuerst sollten
wir uns klarmachen, wie eine Email-Adresse aufgebaut ist.
Vor dem @ Zeichen steht zumindest ein Element, das ein \w
Zeichen ist. (Wir gehen mal davon aus, dass es keine Email-Adresse
gibt, die mit Punkt oder Unterstrich anfängt). Danach
kommen beliebig viele Zeichen (\w Zeichen, Punkt oder Bindestrich,
keine Leerzeichen und auch keine Hyroglyphen wie $%&/ etc.
!).
Dann kommt das @ Zeichen, danach die Domain. Auch die kann
beliebig viele \w, Punkte oder Bindestriche haben. Irgendwann
kommt aber der Punkt vor der Top Level Domain (com, info,
net, org, de, fr, etc.).
Diese hat mindestens zwei (z.B. de) und höchstens vier
(info) Zeichen. Hier sind nur noch Buchstaben möglich.
Das Dach ^ am Anfang und das $ Zeichen am Ende brauchen wir,
um zu verhindern, dass jemand irgendetwas eingibt. Wir wollen,
dass nur eine gültige Email-Adressen eingegeben werden.
Die oben dargestellte Struktur einer Email-Adresse wird von
einer Regular Expression abgebildet. Wir haben irgendein Zeichen
\w. Dann kommt entweder ein \w Zeichen, ein Punkt oder ein
Bindestrich. Davon soll es mindestens eines geben oder beliebig
viele. Anschließend kommt das @ Zeichen. Danach muss
mindestens ein \w Zeichen kommen, dann entweder ein \w Zeichen,
ein Punkt oder ein Bindestrich, im Anschluss ein Punkt. Nach
dem Punkt dürfen nur noch Buchstaben kommen und davon
mindestens zwei und höchstens vier. $test ist also 1,
wenn die Email-Adresse gültig ist.
Einfach mal ausprobieren!
|
Praktisches Beispiel: Den Namen eines Bildes ermitteln
|
|
Ein anderes Problem, welches in der Internet
Programmierung häufig auftritt: Unter Gästebuch
mit Bildupload stoßen wir auf das Problem, dass
wir den gesamten Pfad zu einer Datei haben, wir aber eigentlich
nur den Namen der Datei wollen (z.B. c:\Eigene Dateien\Bilder\Berlin\telespargel.jpg
- telespargel.de)
Dies ist mit einer Regular Expression leicht zu verwirklichen.
$pfad="c:/Eigene Dateien/Bilder/Berlin/telespargel.jpg";
$pfad=~m!.*/(.*)!;
print $1;
$1 ist in diesem
Fall der Name der Datei (telespargel.jpg). Der Punkt steht
für ein x-beliebiges Zeichen, dieses wiederum soll null
mal oder beliebig oft auftauchen. Es soll hier greedy sein,
das heißt der Stern greift nicht durch bis zum ersten
Slash sondern bis zum letzten. Was danach kommt, wollen wir
haben, folglich klammern wir es, so dass es in der Sondervariablen
$1 gespeichert wird.
|
Regular Expressions in Verbindung mit substitution, split
und grep |
|
Bis jetzt haben wir Regular Expression nur
in Verbindung mit dem Match Operator kennengelernt. Sie können
aber auch mit der Split-, der Grep Funktion sowie dem Substitution
Operator genutzt werden. Das schauen wir uns jetzt mal genauer
an. Ein praktisches Beispiel ist das Eliminieren von Html
Tags. Bei Gästebüchern, Foren, Anzeigenmärkten,
Auktionen, Chats, etc. ist es nicht beabsichtigt, dass der
User Html Tags eingeben kann. (Öffnet er z.B. einen Table
und schließt ihn nicht mehr, besteht die Möglichkeit,
dass die ganze Anwendung zerschmettert wird.)
Wie Html Tags eliminiert werden, zeigt das folgende Beispiel.
|
Praktisches Beispiel: HTML Tags eliminieren |
|
$html="<html><head><title>test</test></head><body>Das
ist das, was übrigbleiben soll</body></html>";
$html=~s/<.*?>/ /g;
print $html;
Das Ergebnis ist dann:
test Das ist das,was übrgbleiben
soll
Der Substitution
Operator hat diese Form:
s/was_ersetzt_werden_soll/durch_was_es_ersetzt_werden_soll/optionen(g,
i, etc.). Den Binding Operator kennen wir schon vom
Match Operator. Er lenkt den Operator von der Default Variable
$_ auf die Variable vor dem Gleichheitszeichen. Das, was ersetzt
werden soll, ist in diesem Fall eine Regular Expression.
Interessant ist hier das ?, welches von greedy auf nicht greedy
umstellt. Wäre der Stern greedy, würde er durchgreifen
bis bis zum letzten >. Das heißt, $html wäre nach
der Operation einfach leer. Ersetzt werden soll ist in diesem
Beispiel einfach durch ein Leerzeichen. (Jeder Html Tag wird
durch ein Leerzeichen ersetzt.)
|
Praktisches Beispiel: Links in den image tag einbinden |
|
Noch ein Beispiel aus der Praxis. Nehmen wir
mal an, wir programmieren einen Chat. In diesen sollen die
User Hyperlinks zu Bildern eingeben können (z.B http://www.banane.de/banane.jpg.)
Dies soll dann als Bild erscheinen, muss also folglich zu
<img src=http://www.banane.de/banane.jpg>
umgebaut werden. Die User sollen beliebig viele
Bilder einbauen können.
Die Lösung für dieses Problem sieht dann so aus:
$html="dies ist
ein bild http://www.banane.de/bilder/banane.jpg
und das ist noch eines http://www.tam-tam.de/bilder/ich.jpg
,
wir haben sogar ein drittes nämlich http://www.tingeltangel.de/toll/wessnich.gif
und auch eines das den header weglässt also www.yahoo.de/bilder/test.png";
$html=~s/((http:\/\/|www).*?\.(jpg|gif|png))\b/<img src=..\/..\/perl\/handbuch\/$2>/g;
print $html;
Als Ergebnis erhalten wir
C:\testordner>perl testo.pl
dies ist ein bild <img src=../../perl/handbuch/http://>
und das ist noch eines <img src=../../perl/handbuch/http://>
,
wir haben sogar ein drittes nõmlich <img src=../../perl/handbuch/http://>
und auch eines das den header weglõsst also <img
src=../../perl/handbuch/www>
C:\testordner>
Dieser Ausdruck hat jetzt ein paar Neuheiten.
Das Slash Zeichen muss escaped werden, weil es sonst einen
Kleinkrieg mit der Begrenzung der Regular Expression führt.
Neu ist der Balken | innerhalb (jpg|gif|png). Bilder können
im Internet nur auf jpg, png oder gif enden. Folglich muss
man erzwingen, dass die gesuchte Z eichenkette, der virtuelle
Pfad zu dem Bild, entweder auf jpg, gif oder png endet. (|
der Balken ist innerhalb einer Regular Expression das Zeichen
für oder).
Manche User schreiben anstelle http:// gleich www . Also muss
die Zeichenkette, die für den virtuellen Pfad zu dem
Bild steht, entweder mit http:// oder mit www beginnen.
Diese Regular Expression hat noch eine weitere interessanten
Geschichte. Die virtuellen Pfade zu den Bildern werden einer
nach dem anderen rausgefischt und in $2 abgespeichert. (Option
g ist eingeschaltet) $2 wiederum wird dann verwendet um den
entsprechenden Html Tag zusammenzubauen.
|
Praktisches Beispiel: Mit grep und Regular Expression
bestimmte Elemente eines Arrays finden |
|
Wie oben bereits erwähnt, können Reguar Expressions
auch mit grep verwendet werden. Mit grep kann man sich aus
einem Array bestimmte Elemente mit bestimmten Eigenschaften
rausfischen und an einen Array übergeben.
Ein Beispiel sagt mehr als tausend Worte.
@orginal=("Andres Ehmann","Maria Martínez","Shokufeh Mahmoodzadeh","Werner Binsengrün");
@gefischt=grep(/en|an/,@orginal);
print @gefischt;
Das
setzt dann Andres Ehmann auf den Schirm, weil das an enthalten
ist, und Werner Binsengrün (en).
Nützlich ist dies, wenn man z. B. aus einem Array mit
Email-Adressen diejenigen rausfischen will, die die Domain
de haben.
@orginal=("Andres_Ehmann@web.de","heiner@snafu.de","infos@siemens-ag.com",
"info@powernet.uk","schulungen@infso24.de");
@gefischt=grep(/.*\.de/,@orginal);
print @gefischt;
Dieser
Ausdruck liefert dann Andres_Ehmann@web.de, heiner@snafu.de
und schulungen@infos24.de. Thats what we want.
Wir hatten bei Funktionen
zur Bearbeitung von Zeichenketten den Split Operator
kennen gelernt, der eine Zeichenkette an einem Delimiter trennt
und in einen Array einliest. Das mag theoretisch erscheinen,
aber es sind Fälle denkbar, bei denen der Delimiter (das
Zeichen, welches einen Teil vom anderen trennt) nicht genau
bekannt ist. In der Bioinformatik z.B. beabsichtigt man aus
einem DNA Strang die einzelnen Gene rauszufischen. Das eine
Gen ist aber vom anderen unter Umständen durch die gleichen
Basenpaare getrennt. Was machen wir jetzt? Richtig! Ein Beispiel:
$banane="Apfel und Birnen oder Kirschen und Pampelmusen oder Himbeeren und Kiwis oder Mangos";
@bananen=split(/und|oder/,$banane);
foreach $himbeere(@bananen)
{
print "$himbeere \n";
}
Da kommt dann
Apfel Birnen Kirschen Pampelmusen Himbeeren Kiwis Mangos raus,
weil und bzw. oder als Delimiter erkannt wird.
Überraschend ist, dass mit der Funktion
glob Regular Expressions nicht funktionieren. Mit einer Kombination
aus readdir und grep können wesentlich komplexere Problemen
gelöst werden
(siehe Arbeiten
mit Verzeichnissen)
glob kennt nur das joker Zeichen:
chdir("c:/sambar/docs");
@kirsche=(glob("*.htm"));
print @kirsche;
Hier funktioniert
glob nicht mehr
chdir("c:/sambar/docs");
@kirsche=(glob("*.htm|html"));
print @kirsche;
| |
Alles
noch im Kopf? Ansonsten einfach nochmal die Beispiele
ansehen. |
/
|
Begrenzung der
Regular Expressions |
| \ |
Maskierung |
| $ |
die Regular Expression
wird nur gefunden, wenn sie am Ende des Bereichs
steht |
| ^ |
die Regular Expression
wird nur gefunden, wenn sie am Anfang des Bereichs
steht |
| | |
hält alternative
Ausdrücke auseinander |
| i |
Groß- /Kleinschreibung
wird ignoriert (indifferent) |
| g |
alle Vorkommen
suchen (general) |
| \w |
ein Wordelement
[a-zA-Z _ 1234567890] |
| \W |
kein Wordelement
|
| \d |
eine Ziffer [1234567890]
|
| \D |
keine Ziffer |
| \b |
mit /b nach einer
Regular Expression wird diese nur gefunden, wenn
ein Wort damit endet. |
| \b |
mit /b vor einer
Regular Expression wird diese nur gefunden, wenn
ein Wort damit anfängt. |
| + |
eine oder mehrere
Wiederholungen des Zeichens, das vor dem Pluszeichen
steht |
| * |
keine, eine oder
mehrere Wiederholungen des Zeichens, das vor dem
Sternzeichen steht |
| ? |
kein oder einmaliges
Vorkommen des davorstehenden Zeichens. |
| (
) $1 |
Speichern des Inhaltes
der runden Klammern in die Sondervariable $1 |
| [
ead] |
e, a oder d |
| {
2,5} |
mindestens 2 maximal
5 |
| [^
] |
das Dach in der
eckigen klammer negiert den Inhalt |
| m |
der Match Operator
geht im Default auf die Sondervariable $_ |
|
~ |
der Binding Operator
lenkt den Operator von der Default Variable $_ auf
die Variable vor dem Gleichheitszeichen. |
|
s |
der Substitution
Operator hat die Form s/was_ersetzt_werden_soll/durch_was_es_ersetzt_werden_soll/ |
|
split |
trennt eine Zeichenkette
an einem Delimiter und liest diese in einen Array
ein |
|
grep |
fischt aus einem
Array bestimmte Elemente mit bestimmten Eigenschaften
heraus und übergibt diese an einen Array |
|
|