# Ablaufsteuerung

There's more than one way to do it!
Larry Wall

# If und unless

Bedingte Anweisungen mit if kennen Sie bereits aus JavaScript, und auch die Syntax unterscheidet sich in Perl nicht allzu sehr. Anweisungen mit if sind vorprüfende Anweisungen, d. h., bevor der Anweisungsblock überhaupt ausgeführt wird, wird überprüft, ob die angegebene Bedingung erfüllt ist. Diese Bedingung wird in runden Klammern nach if notiert.

if([Bedingung])  
{  
  [Anweisungsblock]  
}

Bedingungen

Als Bedingung können Sie nun die verschiedensten Kombinationen aus logischen und Vergleichsoperatoren notieren. Im Anweisungsblock selbst folgen dann die auszuführenden Anweisungen.

if($passwort == "geheim")  
{  
  print "Passwort korrekt. Sie dürfen weiter.";  
}

Dieses Beispiel überprüft, ob der Wert des Skalars $passwort gleich "geheim" ist. Ist dies der Fall, wird mit der print-Anweisung ein Text ausgegeben.

Das Beispiel behandelt nur den Fall einer erfüllten Bedingung. Um auch den Fall zu behandeln, wenn die Bedingung nicht erfüllt ist, notieren Sie nach dem ersten Anweisungsblock das Schlüsselwort else und einen weiteren Anweisungsblock.

if([Bedingung])  
{  
  [Anweisungsblock für erfüllte Bedingung]  
}  
else  
{  
  [Anweisungsblock für nicht erfüllte Bedingung]  
}

Um nun das Beispiel mit dem Passwort für den Fall zu erweitern, dass $passwort nicht der Zeichenkette geheim entspricht, hängen Sie einfach einen else-Anweisungsblock an, in dem Sie die auszuführenden Anweisungen notieren.

if($passwort == "geheim")  
{  
  print "Passwort korrekt. Sie dürfen weiter.";  
}  
else  
{  
  print "Passwort falsch. Sie dürfen NICHT weiter.";  
}

Nun werden beide Fälle behandelt: die korrekte Eingabe und die falsche Eingabe des Passwortes.

# elsif

Für den Fall der Fälle, dass Sie mehrere if-Abfragen miteinander verketten möchten, gibt es die spezielle Anweisung elsif. Die entsprechende Syntax lautet:

if([Bedingung])  
{  
  [Anweisungsblock für erfüllte Bedingung]  
}  
elsif([Bedingung])  
{  
  [Anweisungsblock für erfüllte Bedingung]  
}  
else  
{  
  [Anweisungsblock für nicht erfüllte Bedingung]  
}

Die Verwendung der elsif-Anweisung in einem solchen Konstrukt lässt sich beliebig oft wiederholen. Falls die Bedingung nach if nicht erfüllt ist, wird die Bedingung nach elsif geprüft. Ist auch diese Bedingung nicht erfüllt, wird schlussendlich der else-Anweisungsblock ausgeführt.

Gerade dann, wenn Sie mehrere Bedingungen überprüfen müssen, die miteinander verknüpft sind, ist die Verwendung einer if-elsif-else-Anweisung besonders hilfreich.

Ein einfaches Beispiel für eine solche Anweisung ist die Überprüfung eines Skalars auf drei mögliche Werte.

if($zahl = 1)  
{  
  print "Der Wert ist 1";  
}  
elsif($zahl = 2)  
{  
  print "Der Wert ist 2";  
}  
else  
{  
  print "Der Wert ist weder 1 noch 2.";  
}

# unless

Um zu prüfen, ob eine Bedingung nicht erfüllt wird, können Sie die Bedingung mit ! oder not umkehren, oder Sie notieren anstelle von if die Anweisung unless. Anstelle von true (wahr) wird dann von der Bedingung false (unwahr) erwartet.

unless($passwort == "geheim")  
{  
  print "Passwort falsch. Sie dürfen NICHT weiter.";  
}  
else  
{  
  print "Passwort korrekt. Sie dürfen weiter.";  
}

Dieses Beispiel entspricht dem am Anfang des Kapitels stehenden, mit dem Unterschied, dass die beiden Anweisungsblöcke vertauscht sind.

# do-Schleife

Schleifen dienen in Programmen dazu, bestimmte Anweisungen so oft zu wiederholen, solange eine Bedingung erfüllt ist, oder so lange wiederholt zu werden, bis eine Bedingung erfüllt ist. Im ersten Fall werden sie vorprüfende und im zweiten nachprüfende Schleifen genannt.

Zur Gruppe der nachprüfenden Schleife gehört die do-Schleife. Der Unterschied zwischen den Schleifengruppen besteht im Zeitpunkt der Bedingungsprüfung. Bei vorprüfenden Schleifen wird zuerst die Bedingung geprüft und anschließend der Anweisungsblock ausgeführt. Bei nachprüfenden Schleifen wird erst der Anweisungsblock ausgeführt und anschließend auf die Bedingung geprüft. So wird bei nachprüfenden Schleifen der Anweisungsblock immer mindestens einmal durchlaufen, während es bei vorprüfenden Schleifen passieren kann, dass der Anweisungsblock nie durchlaufen wird.

Die Syntax für eine do-Schleife sieht folgendermaßen aus:

do {  
  [Anweisungsblock]  
} until([Bedingung]);

Der Anweisungsblock einer do-Schleife wird also so lange durchlaufen, bis die Bedingung erfüllt ist. Ein Beispiel:

my $i = 0;  
do {  
  print $i;  
  $i++;  
} until($i = 10);

Dieses Beispiel gibt die Zahlen von 0 bis 9 aus, da $i nach der Ausgabe um 1 erhöht wird. Sobald $i also den Wert 10 erreicht hat, wird die Schleife beendet.

# Variante mit while

Es ist auch möglich, die Bedingung umzukehren, d. h., dass die Schleife so lange durchlaufen wird, wie die Bedingung erfüllt ist. Die Syntax lautet:

do {  
  [Anweisungsblock]  
} while([Bedingung]);

Das passende Beispiel ist folgendes:

my $i = 0;  
do {  
  print $i;  
  $i++;  
} while($i < 10);

Auch diese Schleife gibt die Zahlen von 0 bis 9 aus. Sobald $i den Wert 10 erreicht hat, wird die Schleife beendet, da die Bedingung zum Ausführen des Anweisungsblocks »solange $i kleiner 10 ist« lautet.

# for-Schleife

Die for-Schleife ist eine vorprüfende Schleife. Der Anweisungsblock einer solchen Schleife wird also nur dann ausgeführt, wenn die Bedingung erfüllt ist. Das Besondere ist jedoch, dass Sie einen Startwert, eine Bedingung und eine Anweisung definieren können, die bei jedem Schleifendurchlauf ausgeführt werden. Eine for-Schleife ist somit wesentlich flexibler als eine do-while- oder do-until-Schleife.

for([Startwert]; [Bedingung]; [Anweisung])  
{  
  [Anweisungsblock]  
}

Als Startwert können Sie einer Variablen einen Wert zuweisen bzw. sie sogar definieren. Sie besitzt dadurch nur für diese Schleife Gültigkeit. Als Bedingung können Sie wiederum jede erdenkliche Kombination aus logischen Operatoren und Vergleichsoperatoren notieren. Der Erhöhungsschritt ist frei wählbar, wobei im Normalfall der Wert der Variablen um 1 erhöht wird. Ein Beispiel:

for(my $i = 0; $i < 10; $i++)  
{  
  print $i;  
}

Dieses Beispiel gibt die Zahlen von 0 bis 9 aus. Bei jedem Schleifendurchlauf wird der Wert von $i um 1 erhöht ($i++). Die Schleife wird nur ausgeführt, solange $i kleiner als 10 ist.

# while-Schleife

Die while-Schleifen gehören ebenfalls zur Gruppe der vorprüfenden Schleifen. Sie werden also nur dann ausgeführt, wenn die Bedingung erfüllt ist, und beendet, wenn die Bedingung nicht mehr erfüllt ist.

while([Bedingung])  
{  
  [Anweisungsblock]  
}

Das durch Verwendung der while-Schleife geänderte Beispiel lautet so:

my $i = 0;  
while($i < 10)  
{  
  print $i;  
  $i++;  
}

Auch dieses Beispiel gibt wieder die Zahlen von 0 bis 9 aus. Die Schleife wird nämlich nur durchlaufen, solange $i kleiner als 10 ist. Andernfalls wird die Schleife beendet.

# while und Hashes

Eine besondere Form der while-Schleife gibt es für Hashes. Damit lassen sich Hashes Element für Element durchlaufen und der Schlüssel und der Wert des Elements einzelnen ausgeben. Sie machen sich dabei die Methode each zunutze.

Die each-Methode traversiert alle Elemente eines Hashs und gibt den Schlüssel und den Wert des Elements zurück. Als Parameter erwartet die Methode den Hash, der traversiert werden soll.

my %capitols = (Deutschland => "Berlin",  
                Frankreich => "Paris",  
                England => "London",  
                Spanien => "Madrid");  
my $key;  
my $value;  
while(($key,$value) = each(%capitols))  
{  
  print "Die Hauptstadt von $key ist $value";  
}

Dieses Beispiel würde die folgende Ausgabe produzieren:

Die Hauptstadt von Frankreich ist Paris
Die Hauptstadt von Deutschland ist Berlin
Die Hauptstadt von England ist London
Die Hauptstadt von Spanien ist Madrid

Dies ist also eine sehr bequeme Methode, alle Elemente eines Hashs zu ermitteln und zu verarbeiten. Natürlich sind die Möglichkeiten nicht nur auf das Ausgeben der Schlüssel und Werte beschränkt.

# foreach-Schleife

Die foreach-Schleife hat eine ähnliche Aufgabe wie die spezielle Variante der while-Schleife mit each, mit dem Unterschied, dass sie für Listen gedacht ist. Auch die foreach-Schleife ist eine vorprüfende Schleife, und als Bedingung wird eine Liste angegeben. Nacheinander wird jedes Element der Liste in der Schleife verfügbar gemacht. Sobald alle Elemente der Liste abgearbeitet wurden, wird die Schleife beendet.

foreach([Bedingung])  
{  
  [Anweisungsblock]  
}

Den Wert des gerade aktuellen Elements stellt die Schleife im Skalar $_ zur Verfügung.

my @cities = ("Berlin","Hamburg","Bremen","München","Stuttgart","Köln","Frankfurt/Main");  
foreach(@cities)  
{  
  print $_;  
}

Die Ausgabe dieses Beispiels lautet:

Berlin
Hamburg
Bremen
München
Stuttgart
Köln
Frankfurt/Main

Wenn Sie den Wert des aktuellen Elements jedoch in einem anderen Skalar als $_ speichern wollen, müssen Sie dies explizit mit angeben.

my @cities = ("Berlin","Hamburg","Bremen","München","Stuttgart","Köln","Frankfurt/Main");  
my $city;  
foreach $city (@cities)  
{  
  print $city;  
}

Die Ausgabe dieses Beispiels entspricht dem vorherigen.

# Spezielle Notation

Besonders interessant ist, dass Perl die zu verwendende Schleife automatisch erkennen kann. Immerhin sind sich die for- und foreach-Schleife semantisch sehr ähnlich. Anstatt eine Liste anzugeben, können Sie auch als Bedingung eine Liste definieren. Der Code

for("A".."Z")  
{  
  print $_;  
}

würde die folgende Ausgabe erzeugen:

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Sie könnten auch anstelle der Buchstaben von A bis Z einen Zahlenbereich angeben.

for(1..5)  
{  
  print "$_. Durchlauf";  
}

Dies ergibt die folgende Ausgabe:

1. Durchlauf
2. Durchlauf
3. Durchlauf
4. Durchlauf
5. Durchlauf

# Schleifensteuerung

Mit speziellen Anweisungen ist es möglich, das Verhalten einer Schleife direkt zu beeinflussen.

# Durchlauf wiederholen

Mit der Anweisung redo können Sie einen Schleifendurchlauf wiederholen, ohne dass die Bedingung erneut überprüft wird.

my $i = 0;   
while($i < 10)  
{  
  $i++;  
  if($i == 3) { redo };  
  print "$i<br>";  
}

Dieses Beispiel gibt die Zahlen von 1 bis 10 aus, mit Ausnahme der Zahl 3. Sie wird nicht übergeben, da vor der print-Anweisung eine Abfrage stattfindet. Die Anweisung überprüft, ob $i den Wert 3 hat, und wiederholt in diesem Fall die Schleife.

# Schleife abbrechen

Mit der Anweisung last können Sie eine Schleife sofort abbrechen, ohne Rücksicht auf die Bedingung.

my $i = 0;  
while(1)  
{  
  $i++;  
  print "$i<br>";  
  if($i == 5) { last };  
}

Dieses Beispiel ist übrigens eine klassische Endlosschleife, da die Bedingung 1 immer erfüllt ist. Diese Schleife würde also den Bildschirm mit Nullen füllen, bis entweder das Perl-Script durch den Server gestoppt wird oder der Benutzer die Ausführung des Scripts abbricht, wenn nicht die Anweisung

if($i == 5) { last };

notiert worden wäre. Diese führt nämlich dazu, dass die Schleife abgebrochen wird, sobald $i den Wert 5 hat.

# Durchlauf überspringen

Den aktuellen Durchlauf können Sie mit der Anweisung next überspringen.

my $i = 0;  
for(my $i = 0; $i < 10; $i++)  
{  
  if($i == 3) { next };  
  print "$i<br>";  
}

Dieses Beispiel gibt die Zahlen von 0 bis 9 aus, überspringt dabei aber die Zahl 3.

# Zusammenfassung

  • Es gibt vorprüfende und nachprüfende Schleifen.
  • Bei vorprüfenden Schleifen kann es vorkommen, dass der Anweisungsblock gar nicht ausgeführt wird.
  • Bei nachprüfenden Schleifen wird der Anweisungsblock mindestens einmal durchlaufen.
  • Mit den Anweisungen next, redo und last lassen sich die Schleifen explizit steuern.

# Fragen und Übungen

  1. Worin bestehen die beiden Unterschiede zwischen der for-Schleife und der do-until-Schleife?
  2. Was ist das Besondere an der for-Schleife?
  3. Wofür wird die foreach-Schleife verwendet?
  4. Schreiben Sie ein vollständiges Perl-Script, das den Schlüsselnamen und Wert eines Hashs in einer HTML-Tabelle ausgibt!