cgicorner.ch

Informationen rund um Perl/CGI

Sie sind hier: Home > CGI Hilfe > Tutorial > Kapitel 6 - Schleifen

Tutorial - Kapitel 6: Schleifen

Voraussetzungen für dieses Kapitel

  • Webserver mit Perl/CGI-Unterstützung

Einleitung

In diesem Kapitel lernen wir die verschiedenen Schleifen von Perl kennen, welche wir später sicher häufig brauchen werden. Die Vorteile von Arrays und Hashes werden nun auch sichtbar.

FOR-Schleife

Die for-Schleife bezeichnet eine Schleife, die in der Regel eine vordefinierte Anzahl durchlaufen wird. Aber schauen wir uns auch hier wieder ein Beispiel an (for.cgi):

#!/usr/bin/perl
print "Content-type: text/html\n\n";
@monate=("Januar","Februar","März","April","Mai","Juni",
"Juli","August","September","Oktober","November","Dezember");
print "<html><body>";
for ($i=0;$i<=$#monate;$i++) {
  print "Der ".($i+1).". Monat im Jahr ist der $monate[$i]<br/>";
}
print "</body></html>";

Wenn wir das Script ausführen werden wir eine Ausgabe erhalten, die uns die zwölf Monate aufzählt, aber schauen wir das mal ganz genau an...

Zuerst definieren wir ein Array @monate, in das wir die Monate der Reihe nach abspeichern (Erinnern Sie sich? Ein Array beginnt mit dem nullten Eintrag, also $monate[0]="Januar"; $monate[1]="Februar"; etc.).

Nun kommt die komische for-Schleife, diese ist wie folgt aufgebaut:

for (Startvariable;Bedingung;Aktion beim Durchlauf) {
  Anweisungen, die in einer Schleife ausgeführt werden
}

Wir starten also die for-Schleife und setzen beim Start die Variable $i auf "0" ($i=0). Danach legen wir die Bedingung fest, wie lange die Schleife durchlaufen werden soll, nämlich solange die Variable $i einen Wert kleiner oder gleich dem letzten Eintrag des Arrays @monate hat ($i<=$#monate). Bei jedem Durchgang erhöhen wir den Wert der Variable $i um 1 ($i++). Ausgeführt in der Schleife werden alle Anweisungen zwischen { }.

Spielen wir das ganze einmal für die ersten und letzten paar Einträge durch:

  • FOR-Schleife wird initalisiert. $i hat den Wert 0;
  • Bedingung noch wahr? Ja! 0 ist kleiner oder gleich 11
  • Durchlaufe Schleife: Ausgabe "Der 1. Monat im Jahr ist der Januar". Das 1 erreichen wir durch ($i+1) (also 0+1=1), Januar ist der $ite Eintrag des Arrays @monate ($monate[$i])
  • FOR-Schleife am Ende. "Aktion beim Durchlauf" ($i++) wird ausgeführt und die Schleife beginnt von vorne. $i hat jetzt den Wert 1
  • Bedingung noch wahr? Ja! 1 ist kleiner oder gleich 11
  • Durchlaufe Schleife: Ausgabe "Der 2. Monat im Jahr ist der Februar".
  • FOR-Schleife am Ende. "Aktion beim Durchlauf" wird ausgeführt und die Schleife beginnt von vorne. $i hat jetzt den Wert 2
  • Bedingung noch wahr? Ja! 2 ist kleiner oder gleich 11
  • Durchlaufe Schleife: Ausgabe "Der 3. Monat im Jahr ist der März".
  • FOR-Schleife am Ende. "Aktion beim Durchlauf" wird ausgeführt und die Schleife beginnt von vorne. $i hat jetzt den Wert 3
  • ........
  • FOR-Schleife am Ende. "Aktion beim Durchlauf" wird ausgeführt und die Schleife beginnt von vorne. $i hat jetzt den Wert 11
  • Bedingung noch wahr? Ja! 11 ist kleiner oder gleich 11
  • Durchlaufe Schleife: Ausgabe "Der 12. Monat im Jahr ist der Dezember".
  • FOR-Schleife am Ende. "Aktion beim Durchlauf" wird ausgeführt und die Schleife beginnt von vorne. $i hat jetzt den Wert 12
  • Bedingung noch wahr? Nein! 12 ist nicht kleiner oder gleich 11 --> Schleife wird beendet!

Hoffentlich ist es jetzt etwas klarer geworden. Hier sehen wir auch die Stärke von Arrays, welche in Schleifen besonders gut sichtbar ist. Hätten wir statt ein Array Variablen genommen ($monat0="Januar"; $monat1="Februar";... wäre diese Schleife schon ziemlich kompliziert. Das sähe dann nämlich so aus (for_bad.cgi):

#!/usr/bin/perl
print "Content-type: text/html\n\n";
$monat0="Januar";
$monat1="Februar";
$monat2="März";
$monat3="April";
$monat4="Mail";
$monat5="Juni";
$monat6="Juli";
$monat7="August";
$monat8="September";
$monat9="Oktober";
$monat10="November";
$monat11="Dezember";
print "<html><body>";
for ($i=0;$i<=++;$i++) {
  if ($i == 0) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat0<br/>";
  } elsif ($i == 1) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat1<br/>";
  } elsif ($i == 2) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat2<br/>";
  } elsif ($i == 3) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat3<br/>";
  } elsif ($i == 4) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat4<br/>";
  } elsif ($i == 5) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat5<br/>";
  } elsif ($i == 6) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat6<br/>";
  } elsif ($i == 7) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat7<br/>";
  } elsif ($i == 8) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat8<br/>";
  } elsif ($i == 9) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat9<br/>";
  } elsif ($i == 10) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat10<br/>";
  } elsif ($i == 11) {
    print "Der ".($i+1).". Monat im Jahr ist der $monat11<br/>";
}
print "</body></html>";

Unser Beispiel mit einem Array hat 8 Zeilen, das mit Variablen hingegen 42! Ist doch eine ziemliche Erleichterung, oder? Faierweise muss man jedoch sagen, dass mein sicherlich nicht mit einer FOR-Schleife und Variablen gearbeitet hätte, sondern die Monate ohne Schleife als direkten Text (print "Der 1. Monat im Jahr ist der Januar<br/>"; print "Der 2. Monat im Jahr ist der Februar<br/>";...) ausgegeben hätte. Aber auch das hätte 16 statt 8, also doppelt so viele, Zeilen benötigt.

foreach-Schleifen

Gerade im Zusammenhang mit Arrays und Hashes werden häufig auch foreach-Schleifen verwendet. Diese sehen im Syntax so aus:

foreach $element (@array) {
  Eine oder mehrere Aktionen, wobei der aktuelle Eintrag des Arrays
  in $element gespeichert ist }

Die foreach-Schleife im Zusammenhang mit Arrays etwas komfortabler als die for-Schleife, bietet jedoch auch eine Funktion weniger: man hat jeweils nur den Wert der aktuellen Position eines Arrays in einer Variable, weiss jedoch nicht, um das wievielte Element es sich handelt. Zum Vergleich das Beispiel mit den Monaten von oben (for-Schleife) mit einer foreach-Schleife (foreach.cgi):

#!/usr/bin/perl
print "Content-type: text/html\n\n";
@monate=("Januar","Februar","März","April","Mai","Juni",
"Juli","August","September","Oktober","November","Dezember");
print "<html><body>";
foreach $monat (@monate) {
  print "$monat<br/>";
}
print "</body></html>";

Wir haben hier keine Möglichkeit, festzustellen, um den wievielten Monat es sich handelt.

Übrigens: Wird bei der foreach-Schleife keine Variable angegeben, so wird der aktuelle Eintrag jeweils in der System-Variable $_ gespeichert. Diese Variable werden wir in Zukunft immer wieder antreffen. Nochmals die gleiche Schleife ohne Variable (foreach1.cgi):

#!/usr/bin/perl
print "Content-type: text/html\n\n";
@monate=("Januar","Februar","März","April","Mai","Juni",
"Juli","August","September","Oktober","November","Dezember");
print "<html><body>";
foreach (@monate) {
  print "$_<br/>";
}
print "</body></html>";

Das Ergebnis ist das gleiche.

Bei Hashes kann man nie eine for-Schleife benutzen, sondern muss immer eine foreach-Schleife benutzen. Dies möchte ich am besten einmal mit dem Umgebungsvariablen-Hash demonstrieren (foreach2.cgi):

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>";
foreach (keys (%ENV)) {
  print "$_ = $ENV{$_}<BR>";
}
print "</body></html>";

Mit wenigen Zeilen können wir so alle Elemente eines Hashes anzeigen: ein ganz klarer Vorteil von Hashes gegenüber "normalen" Variablen! (keys (%ENV)) bedeutet übrigens nichts anderes, als dass die Schlüsselnamen in die Variable gespeichert werden sollen. Die Werte können wir dann mit $ENV{$_} auslesen.

Wichtig im Zusammenhang mit foreach-Schleifen sind noch zwei weitere Befehle:
next; geht zum nächsten Eintrag und beginnt die Schleife von vorn.
last; beendet die Schleife sofort.

while-Schleifen

while-Schleifen werden solange wiederholt, bis eine definierte Bedingung nicht mehr war ist. Beispiel gefällig (while.cgi)?

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>";
srand(); # initialisiert den Zufallsgenerator
$i=0;
while ($i < 45) {
  $i=int(rand(50));
  print "$i<br/>";
}
print "</body></html>";

Dieses Script generiert Zufallszahlen zwischen 0-49 in einer while-Schleife. Diese Schleife wird wiederholt, solange die Zufallszahl kleiner 45 ist.

Noch ganz kurz zur Generierung der Zufallszahl, auch wenn das eigentlich nicht zum Thema gehört: Einmal im Script muss zuerst der Zufallsgenerator initialisiert werden. Dafür ist srand(); zuständig. mit rand(50); wird eine Zufallszahl kleiner 50 generiert. Hierbei handelt es sich jedoch um eine Zahl mit Kommastellen. Da wir nur Ganzzahlen wollen, schneiden wir die Kommastellen mit int(); ab.

while-Schleifen sind auch im Zusammenhang mit der Verarbeitung von Dateien sehr praktisch, dazu aber in einem späteren Kapitel mehr.

do...while-Schleifen

do...while-Schleifen sind eng verwandt mit while-Schleifen. Der einzige Unterschied liegt darin, dass bei einer do...while-Schleife die Bedingung nicht am Anfang, sondern am Ende der Schleife überprüft wird. Unser Beispiel mit den Zufallszahlen wäre mit einer do...while-Schleife noch eleganter, da wir uns die Zeile, mit der wir $i auf "0" gesetzt haben, sparen könnten. Auch hier ein Beispiel dowhile.cgi

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>";
srand(); # initialisiert den Zufallsgenerator
do {
  $i=int(rand(50));
  print "$i<br/>";
} while ($i < 45);
print "</body></html>";

Zusammenfassung

In diesem Kapitel haben wir die verschiedenen Schleifen (for, foreach, while, do...while kennengelernt. Wir wissen jetzt, dass besondern im Zusammenhang mit Schleifen Arrays uns Hashes deutliche Vorteile gegenüber Variablen haben. Zudem wissen wir, dass es in Perl eine Variable $_ gibt, die im Normalfall verwendet wird, wenn keine andere Variable angegeben wird.

Wie geht's weiter?

Kapitel 7 wird das Thema Subroutinen (Funktionen) behandeln.

Im vorherigen Kapitel (5) beschäftigten wir uns mit der IF-Abfrage.

Sie können aber auch zurück zum Inhaltsverzeichnis und dort ein beliebiges anderes Kapitel auswählen.