Mo 28 Aug 2006
Eine kurze Einführung in die Welt der regulären Ausdrücke
Posted by Oliver under Programmierung , Linux , Tutorials[5] Comments
Es gibt in dieser Welt so einige Dinge, um die man am liebsten einen großen Bogen machen möchte: den Gang zur Zulassungsstelle, den fälligen Zahnarztbesuch oder aber auch um ”reguläre Ausdrücke“. Das Dumme ist nur, man macht sich als Programmierer das Leben unnötig schwer, wenn man darauf verzichtet!
Anhand einiger kleiner Beispiele, versuche ich mal die Arbeitserleichterung “reguläre Ausdrücke” näher zu bringen. Und wenn schon denn schon, sind alle Beispiele in Perl, sollten aber auch in PHP oder einer Hochsprache wie Java nachvollziehbar sein.
Situation 1: Ich brauche Ortsnamen die mit “M” beginnen
Die Lösung sieht in Perl wie folgt aus:
#!/usr/bin/perl
use strict;
my @orte = (”Hannover”, “Muenchen”, “Mainz”, “Hamburg”, “Marburg”);
my $einOrt;
foreach $einOrt (@orte)
{
if ($einOrt =~ m/^M/)
{
print $einOrt.”\n”
}
}
Der Mustervergleich findet in der IF-Bedingung mit “$einOrt =~ m/^M/” statt. Die Erläuterung ist ziemlich simpel:
- =~ leitet den Vergelich ein (Beachte: =~ vs. ==)
- m bedeutet, dass wir einen Mustervergleich vornehmen wollen
- ^heißt soviel wie “am Anfang” und
- M heißt “M”
Um die minimalen Unterschiede zu anderen Programmiersprachen aufzuzeigen, hier das obige Beispiel in PHP:
<?php
$orte = array(”Hannover”, “Muenchen”, “Mainz”, “Hamburg”, “Marburg”);
foreach ($orte as $einOrt)
{
if (preg_match(’/^M/’, $einOrt))
{
echo “$einOrt<br/>”
}
}
?>
Es wird die Funktion preg_match verwendet. Dadurch können wir auf eine Einleitung des Vergleich mit “m” verzichten.
Situation 2: Suchen und Ersetzen
Dummerweise müssen wir alle Ortsnamen die ein “burg” im Namen haben, mit einem “schloss” ersetzen:
#!/usr/bin/perl
use strict;
my @orte = (”Hannover”, “Muenchen”, “Mainz”, “Hamburg”, “Marburg”);
my $einOrt;
foreach $einOrt (@orte)
{
if ($einOrt =~ s/burg/schloss/)
{
print $einOrt.”\n”
}
}
Die IF-Bedingung sollte sich hier von selber erklären. “s” bedeutet “substitute” und leitet den Vorgang ein mit dem Suchbegriff “burg” und nachfolgend die Ersetzung “schloss”.
Dieser Vorgang wird nur beim ersten Vorkommen des gesuchten Begriff “burg” vorgenommen. Wenn in einer Zeile alle Vorkommen eines Suchbegriffs ersetzt werden sollen, benötigen wir am Ende des Ausdrucks noch den Modifier “g” (für global). Beispielsweise wollen wir alle “n’s” mit einem “m” ersetzen:
#!/usr/bin/perl
use strict;
my @orte = (”Hannover”, “Muenchen”, “Mainz”, “Hamburg”, “Marburg”);
my $einOrt;
foreach $einOrt (@orte)
{
if ($einOrt =~ s/n/m/g)
{
print $einOrt.”\n”
}
}
Hierbei wird immer zwischen Groß- und Kleinschreibung unterschieden. Falls diese Unterscheidung nicht stattfinden soll, müssen wir dem Modifier “g” noch den Modifier “i” (für “ignore case”) anhängen:
if ($einOrt =~ s/m/n/gi)
Falls wir jetzt mehrere Zeichen auf einmal ersetzen wollen, brauchen wir die eckigen Klammern []. Beispielsweise wollen wir alle Vokale in einem Satz streichen:
#!/usr/bin/perl
use strict;
my $zeile = “Hallo Leute es ist 09:15 Uhr. Ende”
# [aeiou] Alle Vokale werden mit “” ersetzt
if ($zeile =~ s/[aeiou]//gi)
{
print $zeile.”\n”
}
Alles was in unserem Suchmuster innerhalb der eckigen Klammern steht, wird nun ersetzt und zwar mit nix
Das Ganze lässt sich sozusagen negieren. Heißt, alles wird gestrichen, außer die Vokale:
if ($zeile =~ s/[^aeiou]//gi)
Innerhalb der eckigen Klammern bedeutet ^nicht “am Anfang” sondern so viel wie NICHT.
Wir haben aber auch die Möglichkeit, in unserem Beispiel einen Bereich zu ersetzen. Wenn wir z.B. alle Zahlen von 0 bis 9 mit einem Unterstrich ersetzen wollen, müssen wir Folgendes schreiben:
if ($zeile =~ s/[0-9]/_/gi)
Situation 3: Komplizierte Mustererkennung
Als Situation sei gegeben, dass wir KFZ-Kennzeichen überprüfen müssen. Wir gehen davon aus, dass KFZ-Kennzeichen wie folgt aufgebaut sind:
- Zuerst kommen ein bis drei groß geschriebene Buchstaben von A bis Z
- Dann folgt ein Bindestrich
- Danach 0 bis 3 groß geschriebene Buchstaben von A bis Z und
- am Schluss ein bis 4 Zahlen von 0 bis 9
Die Kennzeichen sind beispielsweise in einer Textdatei kfz.txt:
H-GH456
F-MS2207
NOM-T242
H-ZU1
HH-ZU1
HH-ZU
HH-ZUZU1
HHHH-ZU1
Das Perl-Programm sieht wie folgt aus:
#!/usr/bin/perl
use strict;
open(DATEI, “<kfz.txt”);
my @zeilen = <DATEI>
close(DATEI);
my $zeile;
foreach $zeile (@zeilen)
{
if ( $zeile =~ m/^[A-Z]{1,3}\-[A-Z]{0,3}[0-9]{1,4}/)
{
print “Gueltig: “.$zeile.”\n”
}
else
{
print “Ungueltig: “.$zeile.”\n”
}
}
Situation 4: Komplizierte Mustererkennung und Speicherung in Variablen
Jetzt geht es ein wenig härter zur Sache, es wird kryptisch! Sollte uns aber nicht abhalten, diesen letzten Schritt der Einführung durchzustehen. Nehmen wir an, wir haben aus einer Datenbank diverse Links zu Webseiten und FTP-Ordnern bekommen. Es muss eine Möglichkeit geben, dieses für eine Website so aufzubereiten, daß die Verlinkung korrekt dargestellt wird. Wir benötigen also das Protokoll (http oder ftp), eine URL und einen Titel. Jeder Eintrag kommt wie folgt formatiert aus der Datenbank:
{link:http://de.selfhtml.org/{SELFHTML-Seiten}}
Die “Umwandlung” geschieht wie folgt:
#!/usr/bin/perl
use strict;
my $zeile = “{link:http://de.selfhtml.org/{SELFHTML-Seiten}}”
$zeile =~ m/^\{link:(.*):\/\/(.*)\{(.*)\}\}\s*$/;
print “\$1: $1\t\$2: $2\t\$3: $3\n”
Was geschieht hier?
- Es findet eine Mustererkennung statt : m
- Wir gehen an den Satzanfang und Suchen die Sequenz ab “{link:” die bis zum nächsten Vorkommen von “:/” geht. Die “\” sind die sogenannten Escape-Zeichen, die Sonderzeichen markieren! Die normalen Klammern “()” gruppieren alles was innerhalb von diesem Muster vorkommt “(.*)”. D.h. es steht uns später in der Variable “$1″ zur Verfügung
- Die nächste Sequenz geht ab dem Vorkommen von “://” -> “:\/\/” los. Beachte: Die “\” sind die sogenannten Escape-Zeichen, die Sonderzeichen markieren! Sie endet beim nächsten Vorkommen von “{”. Der Inhalt steht uns als “$2″ zur Verfügung
- Gleich direkt daran, wird alles bis zum Vorkommen von }} in die nächste Variable “$3″ gepackt -> “(.*)\}\}”
- “\s*$/” bedeutet, dass ab hier nur noch Leerzeichen (”\s*”) bis zum Zeilenende (”$”) folgen dürften oder halt sofort das Zeilenende.
Leerzeichen bedeutet ‘ ‘, \n, \r oder \t
Die Ausgabe sieht wie folgt aus:
$1: http $2: de.selfhtml.org/ $3: SELFHTML-Seiten
Ich hoffe, dieser kleine Einstieg hat etwas geholfen. Freue mich wie immer über Kommentare, Kritik usw.. Zur Vertiefung sei das Buch Reguläre Ausdrücke. Praxislösungen für PHP, Perl, MySQL und JavaScript empfohlen!