Die zweite Möglichkeit zur Änderung für die Musterfindung, führt im Gegensatz zum Kapitel zuvor, einen einfachen
Ersatz von Zeichenfolgen durch. . Hier der Syntax ...
$string =~ tr/SuchListe/ErsatzListe/;
Ein einfaches Beispiel: Sie wollen alle Buchstaben einer Textdatei die Sie als Kommandozeilenargument mit dem Programm gestartet haben, in Großbuchstaben umwandeln ...
#!/usr/bin/perl -w
use strict;
undef $/;
my $text=<>;
if($text =~ tr/a-z/A-Z/) {
print $text , "\n";
}
In diesem Beispiel wird jedes einzelne Zeichen von der Suchliste durch eines der Zeichen in
ErsatzListe ersetzt.
Die Liste von Zeichen können Sie auch wörtlich schreiben ...
ABCDEF
A-F #ABCDEF
A-CX-Z #ABCXYZ
A-C0-9 #ABC0123456789
Hierzu noch ein paar Beispiele ...
#!/usr/bin/perl -w
$text = "Dieser Text soll für Transliterationen missbraucht werden";
print $text , "\n";
$text =~ tr/a-z/A-Z/; #alles in Grossbuchstaben
print $text , "\n";
$_ = $text;
$anzahl_T = tr/T/T/; #Anzahl von dem Buchstaben T in $text
print "In diesem Text kommen $anzahl_T \"T\" 's vor!\n";
$anzahl_Space = tr/ / /; #Leerstellen in $text
print "In dem Text sind $anzahl_Space Leerstellen vorhanden\n";
An diesem Beispiel können Sie erkennen, dass tr/// im Skalaren Kontex (ohne ~) die Anzahl betroffener Zeichen zurückliefert. Vorrausgesetzt der Inhalt befindet sich in der Standartvariable $_.
Natürlich können Sie auch einzelne Zeichen löschen ...
#!/usr/bin/perl -w
$text = "Dieser Text soll für Transliterationen missbraucht werden";
$text =~ tr/enl/ /; #Buchstaben e n und l entfernen
print $text , "\n";
Was aber tun bei folgender Angabe ...
$text =~ tr/abcd/ABC/;
In diesem Fall werden alle Buchstaben abcd ersetzt duch ABC. Aus
d wird nun aber auch ein C. Um dies zu vermeiden gibt es das Flag
/d das nichtersetzbare Zeichen entfernt ...
$text =~ tr/abcd/ABC/d;
Weitere Flags und Ihre Bedeutung wären ...
- /s - Entstandene Duplikate aus der Ersetzung entfernen
- /d - Nichtersetzte Zeichen entfernen
- /UC - Konvertiert von Unicode nach Latin-1
- /CU - Konvertiert von Latin-1 nach Unicode
Interessant dürfte es sein, den Text von Latin-1 in Unicode und wieder zurück zu konvertieren. Alle 255 darstellbaren Zeichen die es gibt können
Sie so angegeben ...
\0-\xFF
Hier das Beispiel dazu ...
#!/usr/bin/perl -w
$text = "Ein häßlicher Text für Konvertierungen : üäöß";
$text =~ tr/\0-\xFF//CU; #Latin1 -> Unicode
print $text , "\n";
$text =~ tr/\0-\x{FF}//UC; #Unicode -> Latin1
print $text , "\n";
Wichtig ist es zu erwähnen, dass das Ersetzen mit tr/// schneller geht als mit s/// was für Internetanwendungen (CGI-Skripts) wichtig sein dürfte.
Nochmals eine kurze Zusammenfassung ...
- $string =~ m/suchstring/; #Suchen von Schlüsselworten
- $string =~ s/suchstring/ersetztstring/; #Suchen und Ersetzten von Strings
- $string =~ tr/suchliste/ersetztliste/; #Ersatz für einzelne Zeichenfolgen
Die Metazeichen haben Sie schon im ersten Kapitel der Regulären Ausdrücke kennen gelernt. Nun
soll das Ganze noch ein wenig vertieft werden. Anfangen will ich mit dem Metazeichen und
den normalen Zeichen, dem Punkt.
Sollten Sie in einem Satz nach einem Punkt suchen wollen so müssen Sie diesem einem Backslash
voranstellen ...
#!/usr/bin/perl -w
use strict;
my $text = "Die Suche nach dem Punkt.";
if($text=~/\./){
print "Punkt gefunden\n";
}
Hätten Sie stattdessen geschrieben ...
if($text=~/./)
... wäre die Ausgabe zwar auch Punkt gefunden, aber das Metazeichen "." bedeutet in diesem Fall,
dass es sich um ein beliebiges Zeichen (außer newline) handelt.
Wenn Sie nach einzelnen Zeichen suchen, können Sie diese in eckigen Klammern setzen ...
#!/usr/bin/perl -w
use strict;
my $text = "Dieser Text enthaelt 1 Zahl.";
if($text=~/[0-9]/){
print "Zahl gefunden\n";
}
Sollten Sie überprüfen wollen ob der Text ein Zeichen enthält, dass nicht in den eckigen Klammern steht, so brauchen
Sie dieses nur mit dem Zeichen ^ in den eckigen Klammern negieren ...
#!/usr/bin/perl -w
use strict;
my $text = "12343535343566a798";
if($text=~/[^0-9]/){
print "Ein Zeichen gefunden das keine Ziffer ist\n";
}
Sie sehen das Zeichen ^ hat in eckigen Klammern ein andere Bedeutung als das Metazeichen ^ , was ja für das verankern eines Strings am Anfang steht.
Wenn Sie nach Steuerzeichen suchen wollen, machen Sie dies ebenfalls am besten in eckigen Klammern ...
#!/usr/bin/perl -w
use strict;
my $text = "Dieser Text\t enhält Steuerzeichen\n";
my $tab = " ";
my $nwl = "<br>";
if($text=~/[\t\n]/){
print "Steuerzeichen im Text gefunden\n";
$text=~s/[\t]/$tab/;
$text=~s/[\n]/$nwl/;
}
print $text , "\n";
Ein Hinweis noch zum Backslashing wie ...
/\/usr\/bin\/locale\/perl/ #/usr/bin/locale/perl
... können Sie anstatt den ständigen Backslashes die Zeichen zwischen den
Metazeichen \Q....\E stellen ...
/\Q/usr/bin/locale/perl\E/
Somit verliert jedes Metazeichen zwischen \Q und \E seine Bedeutung als Metazeichen.
Als nächstes zum Zero-With-Assertion. Sogenannte Wortbegrenzter und deren Einsatzmöglichkeit ...
#!/usr/bin/perl -w
use strict;
my $text = "wortgrenzen wort verantwortlich antwort ";
my @array=(0);
my $counter=0;
while($counter!=5){
$array[$counter]=$text;
$counter++;
}
$array[0] =~ s/wort/----/g ; #alle wort zu ----
$array[1] =~ s/wort\b/----/g; #alle ....wort am Ende zu ----
$array[2] =~ s/\bwort\b/----/g; #alle wort exakt zu ----
$array[3]=~ s/\bwort/----/g; #alle wort.... am Anfang zu ----
$array[4]=~ s/\Bwort\B/----/g; #alle ...wort... dazwischen zu ----
$counter=0;
foreach(@array){
print "$array[$counter]" , "\n";
$counter++;
}
Die Ausgabe sieht dabei folgendermaßen aus ...
----grenzen ---- verant----lich ant----
wortgrenzen ---- verantwortlich ant----
wortgrenzen ---- verantwortlich antwort
----grenzen ---- verantwortlich antwort
wortgrenzen wort verant----lich antwort
In diesem Beispiel haben wir nur mit dem Wortbegrenzter \b und Nicht-wortbegrenzter
\B gearbeitet.
Nehmen Sie mal an Sie wollen folgenden Text ...
"Dieser Text besitzt\n zwei Newlinezeichen\n "
... zwischen ...
<<<....>>>
... stellen. Wie würden Sie vorgehen. Ihres Wissens nach wahrscheinlich so ...
#!/usr/bin/perl -w
use strict;
my $text = "Dieser Text besitzt\n zwei Newlinezeichen\n ";
$text=~ s/^/<<</mg;
$text=~s/$/>>>/mg;
print $text, "\n";
Nun ja wenn man sich aber die Ausgabe ansieht ...
<<<Dieser Text besitzt>>>
<<< zwei Newlinezeichen>>>
<<< >>>
Das Problem in diesem Beispiel ist, dass durch die Flags /mg die Bedeutung von $ so verändert wurde das \n das Ende des Strings darstellt. Und ^ wird durch dieses Flag als Anfang einer jeden Zeile verwendet. Um dies zu vermeiden gibt es die beiden
Metazeichen \A und \Z, für den Anfang und den Ende eines Strings vor den Newline am Ende ...
#!/usr/bin/perl -w
use strict;
my $text = "Dieser Text besitzt\n zwei Newlinezeichen\n ";
$text=~ s/\A/<<</mg;
$text=~s/\Z/>>>/mg;
print $text, "\n";
Mit dieser Möglichkeit kommen Sie dem Programm schon näher. Jetzt steht
der Text zwischen <<< >>>
Mit Quantifiern lassen sich Teilausdrücke wiederholen. Dabei Unterscheidet man zwischen 2 Arten von
Quantifiern. Zum einen die gierigen, die so viele Zeichen wie möglich schlucken wollen.
Und zum anderen die weniger Gierigen. Der Unterschied zwischen diesen Beiden Versionen, ist das an der Nicht-Gierigen-Version am Ende ein ? - Zeichen steht. Dazu wollen wir uns ein Beispiel ansehen. Zuerst die
gierigen Quantifiern ...
#!/usr/bin/perl -w
use strict;
my $secret = "MasterCard : 55543214543 ";
my @array=(0);
my $counter=0;
while($counter!=6){
$array[$counter]=$secret;
$counter++;
}
$array[0] =~s/\d*/-/; # *=={0,}
$array[1] =~s/\d+/-/; #mindestens 1 Vorkommen
$array[2] =~s/\d?/-/; #gleichwertig zu {0,1}
$array[3]=~s/\d{8}/-/; #Exakt 8 Zahlen ersetzten
$array[4]=~s/\d{1,}/-/; #wie schon \d* mindestens 1 Vorkommen
$array[5]=~s/\d{2,4}/-/; #Mindestens 2 Vorkommen höchstens 4 Vorkommen
$counter=0;
foreach(@array){
print "$array[$counter]" , "\n";
$counter++;
}
Folgende Ausgabe sollten Sie nun erhalten ...
-MasterCard : 55543214543
MasterCard : -
-MasterCard : 55543214543
MasterCard : -543
MasterCard : -
MasterCard : -3214543
Kommen wir nun zur Nichtgierigen Version der Quantifiern ...
#!/usr/bin/perl -w
use strict;
my $secret = "MasterCard : 55543214543 ";
my @array=(0);
my $counter=0;
while($counter!=6){
$array[$counter]=$secret;
$counter++;
}
$array[0] =~s/\d*?/-/; #*=={0,}
$array[1] =~s/\d+?/-/; #mindestens 1 Vorkommen
$array[2] =~s/\d??/-/; #gleichwertig zu {0,1}
$array[3]=~s/\d{8}?/-/; #Exakt 8 Zahlen ersetzten
$array[4]=~s/\d{1,}?/-/; #wie schon \d* mindestens 1 Vorkommen
$array[5]=~s/\d{2,4}?/-/; #Mindestens 2 Vorkommen höchstens 4 Vorkommen
$counter=0;
foreach(@array){
print "$array[$counter]" , "\n";
$counter++;
}
Hier erhalten Sie nun folgende Ausgabe ...
-MasterCard : 55543214543
MasterCard : -5543214543
-MasterCard : 55543214543
MasterCard : -543
MasterCard : -5543214543
MasterCard : -543214543
Am besten kann man die gierige Version von der Nichtgierigen in den Beispielen ...
#gierig
$array[4]=~s/\d{1,}/-/; #wie schon \d* mindestens 1 Vorkommen
$array[5]=~s/\d{2,4}/-/; #Mindestens 2 Vorkommen höchstens 4 Vorkommen
#nicht gierig
$array[4]=~s/\d{1,}?/-/; #wie schon \d* mindestens 1 Vorkommen
$array[5]=~s/\d{2,4}?/-/; #Mindestens 2 Vorkommen höchstens 4 Vorkommen
... unterscheiden. Die gierige Version nimmt das Wort mindestens genau und schluckt alle Zahlen, da
ja keine Grenzen gesetzt wurden. Stellt man dem ganzen ein Fragezeichen ? ans Ende, schon haben
Sie die Nichtgierige Version. Nun werden wirklich nur mindestens Zeichen verschluckt.
Um Teilausdrücke für spätere Verwendungen zu benutzen, werden diese mit Hilfe von runden Klammern gespeichert. Beispiel ...
#!/usr/bin/perl -w
use strict;
my $secret = "Alle guten Dinge der Welt findet man in der Programmiersprache Perl";
$_=$secret;
while(1){
if(/\b\w{3}\b/g){
print "Wort mit 3 Buchstaben gefunden\n";
}
else{last;}
}
Hier werden alle Wörter gesucht mit 3 Buchstaben in unserer Variable $secret. Zwar bekommen
Sie jetzt 3 mal ausgegeben das ein Wort mit 3 Buchstaben gefunden wurde. Aber
welche? Um dies herauszufinden müssen Sie die Teilausdrücke die Sie interessieren einklammern. Der Teilstring der dann gefunden wird, wird in der Variable
$1 gespeichert ...
#!/usr/bin/perl -w
use strict;
my $secret = "Alle guten Dinge der Welt findet man in der Programmiersprache Perl";
$_=$secret;
while(1){
if(/\b(\w{3})\b/g){
print "Wort mit 3 Buchstaben gefunden : $1\n";
}
else{last;}
}
Nun steht nach jedem Schleifendurchlauf ein Wort mit 3 Buchstaben in der Variable $1. Was aber nun wenn man mehrer Wörter als Teilausdrücke speichern will. Dazu gibt es weitere Variablen : $1, $2, $3, $4...usw.
Wenn Sie Beispielsweise aus dem Quelltext einer Webseite alle Links herausziehen wollen ...
#!/usr/bin/perl -w
use strict;
my $links = q!Und <a href="http://www.pronix.de/index.html">hier</a>
kommen Sie zur Hauptseite<br>!;
$_=$links;
if(/.*?(<a href="(.*?)">).*/){
print "Der komplette Link lautet : $1\n";
print "Das Ziel diese Links ist : $2 \n";
}
Die Ausgabe des Textes lautet ...
Der komplette Link lautet : <a href="http://www.pronix.de/index.html">
Das Ziel diese Links ist : http://www.pronix.de/index.html
An dem Beispiel ...
(/.*?(<a href="(.*?)">).*/)
... sehen Sie auch das es möglich ist, in Klammern weitere Klammern zur Speicherung von Teilstrings zu verwenden. Langsam kann man schon erkennen das Reguläre Ausdrücke recht komplex werden können. Hier die Erklärung zu dem eben verwendeten ...
- .*? = Es können beliebige
Zeichen stehen, diese interessieren uns aber nicht (nicht gierig)
- (<a href="(.*?)">) = wir speichern alle <a
href="beliebiger Text"> in $1 und das Ziel (.*?) davon in $2
- .* = die restlichen Zeichen interessieren uns nicht
Dies soll nun ein kleiner Überblick über die Regulären Ausdrücke gewesen sein. Ich hoffe Ihnen damit ein wenig Überblick über diese sehr Umfangreiche Thema verschafft zu haben.
|