ein Kapitel zurück                                           ein Kapitel weiter

Kommen wir nun zu einem Interassanten, wenn nicht dem Interessantesten, Thema in Perl. Der Suche in Texte nach bestimmten Wörtern oder Textpassagen. Aus diesem Grund habe ich auch Perl gelernt. Speziell als Webmaster von vielen Webseiten ist man es oft satt alle Webseiten nach einem bestimmten Wort zu durchsuchen. Besser noch wenn sie vorhaben in CGI eine eigene Suchmaschine für Ihre Webseite zu erstellen.
Zugegeben mit anderen Programmiersprachen ist dies auch zu bewerkstelligen, nur nicht so kurz und einfach wie in Perl.

Bevor wir nun beginnen um nach Wörtern zu suchen benötigen wir eine Textdatei. Welche sie dabei benutzen bleibt ihre Sache. Ich verwende meine Startseite zu www.pronix.de index.html dazu. Da ich annehme das sie sich diesen Kurs heruntergeladen haben dürfte sich diese Datei auch auf Ihrer Festplatte finden.

Nun wollen wir unser erstes Perl-Skript schreiben womit wir nach einem bestimmten Wort in einer Datei suchen........

#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);

open(FH, "< $file")
         or
         die "Konnte $file nicht öffnen\n";

undef $/;

my $search = <FH>;
 if($search =~ m/C-KURS/) {
         print "C-KURS gefunden\n"
         }


Bis zu undef $/ nichts neues für sie. Was bedeutet nun das undef $/ ?
Wir setzen damit die Standardvariable $/ auf einen undefinierten Wert, womit wir den "Schlürfmodus" des Eingabeoperator aktivieren. Dies sorgt dafür das wir den gesamten Text in der Variable $search stehen haben. Nun suchen wir mittels....

$search =~ m/C-KURS/      

...nach dem Wort C-KURS. Dies machen wir mit dem Pattern Matching Operator.....

m//  

Das zu suchende Wort steht dabei zwischen den /-Strichen. Sollte das von Ihnen gesuchte Wort folgende Zeichen enthalten...........

^ . $ | * + / ( ) [ ] { } ?

...müssen sie die mit einem vorangestellten Backslash darstellen oder anstatt den /-Strichen zwischen geschweifte Klammern stellen.........

$search =~ m{$dollar} ;          #Suchbegriff: $dollar    

Der Pattern-Matching Operator m// kann auch abgekürzt werden durch // Auf unser Beispiel.......

$search =~ m/C-KURS/;   

...bezogen ist diese Schreibweise....

$search =~ /C-KURS/;   

.......also die selbe.

Außerdem gibt es auch die Möglichkeit die Schrägstriche des m// - Operators durch andere Zeichen zu ersetzten. Dies hat den Vorteil das z.B. auf die Backslashes in folgenden Beispiel.......

$pfad =~ /\/usr\/bin\/perl/;         

...verzichtet werden kann. Nehmen wir zum Beispiel folgendes Programm.......


#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);
print "Wonach wollen sie in $file suchen : ";
chomp(my $suche=<>);

open(FH, "< $file")
         or
         die "Konnte $file nicht öffnen\n";

undef $/;

my $search = <FH>;
 if($search =~ m/$suche/) {
           print "...... gefunden!\n";
           }


Jetzt nehmen wir an der Benutzer dieses Programms sucht in einer HTML-Datei nach </FORM> Sie wissen zwar jetzt das sie für die Suche folgende Eingabe machen müssen.........

<\/FORM>

Aber die meisten werden dies nicht wissen. Also ersetzen wir einfach die beiden Schrägstriche durch ein anderes Zeichen. Anstatt.....

 if($search =~ m/$suche/)    

...einfach...

 if($search =~ m{$suche})     


...oder...

if($search =~ m,$suche,)   

In diesen Fällen ist aber das Führende m notwendig.

Ein kleiner Tipp noch am Rande..............

my $search = <FH>;
 if($search =~ m{$suche}) {
           print "...... gefunden!\n";
           }


...läßt sich auch verkürtzt schreiben wie.....

print ".....gefunden\n" if <FH>=~ m{$suche};   

Soll die Suche negiert werden müssen sie anstatt =~ einfach die Schreibweise !~ verwenden. Für unser Beispiel hieße dies dann...

print ".....$suche nicht enthalten\n" if !~ m{$suche};   


Hier wird also die print-Anweisung nur Ausgeführt wenn das Gesuchte Wort $suche nicht im Text enthalten ist.

Noch etwas was sie noch zu Pattern-Matching wissen sollten. Wenn sie das Pattern leer lassen wird das Muster verwendet das sie bei der letzten Suche erfolgreich verwendet haben. Hier das Programmbeispiel...

#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);
print "Wonach wollen sie in $file suchen : ";
chomp(my $suche=<>);

open(FH, "< $file")
         or
         die "Konnte $file nicht öffnen\n";

undef $/;

$_=<FH>;
print "\"$suche\" gefunden\n" if $_=~ m/$suche/;
print "Viele Zeilen später.................\n";
print "\"$suche\" erneut gefunden\n" if $_=~m//;


Und wenn wir schon die Standardvariable $_ verwenden können wir auch auf =~ verzichten. Also....

$_=<FH>;
print "\"$suche\" gefunden\n" if /$suche/;
print "Viele Zeilen später.................\n";
print "\"$suche\" erneut gefunden\n" if //;


Der Nachteil an unserem Beispiel zuvor ist aber der, dass sobald wir das entsprechende Wort gefunden haben die Suche eingestellt wird. Dies ist die Voreinstellung von Pattern Matching. Um die Suche fortzusetzen ob mehrere des von uns gesuchten Suchwortes vorhanden sind brauchen wir nur die Option g am Ende des Pattern Matching Operator hinzufügen..........

#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);

open(FH, "< $file")
 or
 die "Konnte $file nicht öffnen\n";


while(my $search = <FH>){ #Zeilenweise einlesen
            if($search =~ m/und/g) {  #Suchen nach dem Wort: und
                     print $. , ".Zeile: \"und\" gefunden\n"
                     }
            }


Mit der Option g am Ende von........

$search =~ m/und/g  


weisen wir unsere Suchoption zu globalen Suche an die nacheinander alle Vorkommen findet. Wenn wir jetzt auch noch wollen das keine Unterscheidung zwischen Groß- und Kleinschreibung stattfindet müssen wir nur noch zusätzlich die Option i hinten anhängen...........

$search =~ m/und/gi;
#Suchen nach dem Wort: und | unabhängig von Groß/Kleinschreibung


Also mit folgenden Optionen können sie den Pattern Matching Operator ausstatten.......

  •          globale Suche die alle Vorkommen findet
  •          Suche unabhängig von Groß- bzw. Kleinschreibung
  •          Suche über das Zeilenende hinweg
  • m         Suche erkennt newline-Zeichen im String als Zeilenende
  • c        Suchposition nicht zurücksetzen bei Fehler
  • o        Suchmuster nur einmal kompilieren.
  • x         Erweiterter Syntax

Nun besteht die Möglichkeit einen Text nach einem bestimmten Muster abzusuchen mit Hilfe von speziellen Zeichen die mit Regulären Ausdrücken verwenden können. Wir wollen z.B. auf meiner Indexseite von www.pronix.de nach den Worten Systemprogrammierung und Hardwareprogrammierung suchen und entsprechende Zeilen ausgeben........

#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);

open(FH, "< $file")
         or
         die "Konnte $file nicht öffnen\n";


while(my $search = <FH>){
           if($search =~ m/(Hardware|System)programmierung/g) {
                   print $. , ".Zeile: $search gefunden\n"
                  }
           }


Was haben wir den hiermit gemacht.............


 if($search =~ m/(Hardware|System)programmierung/g)

Dies stellt eine verkürzte Schreibweise von........

 if( ($search =~ m/Systemprogrammierung/g) ||
     ($search =~ m/Hardwareprogrammierung/g))       


dar. Also stellte eine Schreibweise wie z.B............


/(b|d|g|m)ig/

...wir suchen hier nach den Wörtern big, dig, gig, mig.
In unserem Beispiel wir übrigens 3x etwas gefunden. Was aber jetzt wenn wir alle Wörter ausgeben wollen in denen das Wort "programm" vorkommt? Erweitern wir unser Programm.........


#!/usr/bin/perl -w

use strict;

print "Welche Datei wollen sie durchsuchen : ";
chomp(my $file=<>);

open(FH, "< $file")
         or
         die "Konnte $file nicht öffnen\n";


while(my $search = <FH>){
            if($search =~ m/.programm./gi) {  #Suchen Wort: und
                   print $. , ".Zeile: $search gefunden\n"
                  }
      }


Somit werden alle Zeichenfolgen ausgegeben in denen sich die Zeichenfolge "programm" befindet. Und dies bedeutet schon um einiges mehr gefundener Wörter in der Textdatei. Dieses mal haben wir die Zeichengruppe ' . ' verwendet das ein beliebiges Zeichen sein kann außer \n. Wenn sie die Option s Mitanschließen wird auch diese Zeichen miteingelesen. Später wollen wir eine kleine Suchmaschine basteln mit der wir nach einem bestimmten Suchbegriff im C-Kurs meiner Homepage suchen.

Bevor wir mit dem Kapitel weitermachen wollen wir uns ansehen mit welchen Zeichen man welche Regulären Ausdrücke darstellen kann................

  • .                   findet Zeichen mit Ausnahme von \n
  • (...)             Gruppiert eine Serie von Elementen
  • +                 Geht ein oder mehrmals zum vorhergehenden Muster
  •                  Geht ein oder keinmal zum Muster
  •                  Geht kein oder mehrmals zum Muster
  • [...]              Springt aus dem eingeschlossenen Satz zu einem Zeichen
  • [^...]            Springt aus einem negierten Satz zu einem Zeichen
  • (..|..|..)          Springt zu einem der Alternativen
  • ^                  Springt zum Anfang eines Strings
  • $                 Geht zu Mustern am Ende des Strings
  • {n ,m}         Springt n bis m mal zum Muster
  • {n}              Springt n mal zum Muster
  • {n,}             Springt mindestens n mal zum Muster
  • \n \t....          Geht zu einem Newline oder Tabzeichen..........
  • \b                 Springt zum Rand eines Wortes
  • \B                Springt in die Abgrenzung eines Wortes
  • \d                 Geht zu einer Ziffer
  • \D                Geht zu einer Nicht-Ziffer
  • \s                 Geht zu einem White-Space
  • \S                 Geht zu einem Nicht-White-Space
  • \w                Geht zu einem Alphanumerischen Zeichen
  • \W               Geht zu einem Nicht-Alpanumerischen Zeichen
  • \A                Anfang des Strings
  • \Z                Ende des Strings

Nun wollen wir auch ein paar Beispiele verwenden zum besseren Verständnis wie man dies Regulären Ausdrücke verwendet. Beispiel.......

if($variable =~ /^ba(na){2, 4} $/)   

Wir interpretieren :

  • ^         =       Wir springen zum Anfang des Strings $variable.
  • ba       =       Normale Zeichenkette
  • (na)     =       Wir Gruppieren eine Serie von Elementen
  • {2,4}   =       Wir springen 2 bis 4 mal zum Muster (na)

Das bedeutet unser Ausdruck in if-Anweisung ist wahr wenn das Wort 'banana' (2x) 'bananana' (3x) oder 'banananana' (4x) lautet. Der Ausdruck könnte also genauso lauten.......

if($variable =~ /^ba(nana|nanana|nananana) $/)    

Beide sind gleichwertig. Nächstes Beispiel.......

if($variable =~ /\bProgramm\b/)       

Damit suchen wir exakt nach dem Wort Programm und nicht Programme oder Programmierer. Dies daher weil wir mit \b einen Wortbegrenzer eingesetzt haben.

Weiteres Beispiel......

$variable = " Juli 15, 2001, "
($monat, $tag, $jahr) = $variable =~ /\s*(\S*)\s+(\d+)\D+(\d{4}))/;

Wir interpretieren wieder......

  • \s*        =     alle anführenden Leerzeichen überspringen
  • (\S*)    =      alle nicht Zeichen die nicht Leerzeichen sind an die Variable $monat übergeben
  • \s+       =      wieder alle Leerzeichen überspringen
  • (\d+)    =      alle Ziffern in $tag
  • \D+      =      alle Nicht-Ziffern überspringen
  • (\d{4}) =     alle 4 Ziffern an die Variable $jahr übergeben

Weiteres Beispiel......

#!/usr/bin/perl -w

use strict;

print "Bitte geben sie eine mindest 4 Stellige Zahl ein : ";
chomp(my $zahl=<>);

if($zahl =~ m/\d{4}?/) {
      print "Zahl OK\n";
     }
else{
      print "Der Zahlbereich wahr kleiner wie 4 Stellen\n";
     }


Das Zeichen ^ steht ja für den Anfang der Zeile und $ für das Ende der Zeile...

#!/usr/bin/perl -w

use strict;

my $text = "Hallo Welt ich lerne Regulaere Ausdruecke kennen";

$_=$text;
if (/^Hallo/){print "Hallo am Anfang des Textes gefunden\n";}
if(/Hallo/)    {print "Hallo gefunden\n";}

if(/^Welt/) {print "Welt am Anfang gefunden\n"#wird nicht ausgegeben
if(/Welt/)    {print "Welt gefunden\n";}

if (/kennen$/) {print "\"kennen\" steht am Ende\n";}
if (/kennen/)   {print "\"kennen\" gefunden\n";}
if (/^kennen/)  {print "\"kennen\" steht am Anfang\n";} 
#wird nicht ausgegeben

print "Der 1. Buchstabe des Strings lautet " ,  /^(.)/ , "\n";
print "Der letzte Buchstabe ist ein ",  /(.)$/  , "\n";
print  /^(.*)$/ , "\n";
#Gibt kompletten String aus von Anfang ^ bis Ende $

Der Reguläre Ausdruck...

print /^(.*)$/ , "\n";  

...sieht schlimmer aus als er ist :

  • ^ = Anfang der Zeile
  • (.*) = Wir gehen mehrmals zum Muster . (was für ein Zeichen steht)
  • $ = Ende der Zeile (Hätten wir uns auch sparen können)

Was aber wenn unser Text so aussieht...

my $text = "Hallo Welt ich lerne\n Regulaere Ausdruecke kennen";     

Wie gebe ich da den kompletten Text aus, da ja ein Newline-Zeichen dazwischen ist?

print /^(.*)$/mg , "\n";    

Wir verwenden das Flag /m , was ja bedeutet das Strings aus mehreren Zeilen bestehen können. Und desweiteren verwenden wir das Flag /g damit die Suche weiter nach vorne auf den Anfang der nächsten Zeile verschoben wird.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf