SELFHTML/Quickbar CGI/Perl Perl-Sprachelemente

| ## Schleifen und Sprungbefehle
| Schleifen mit while/until Schleifen mit do..while/until Schleifen mit for/foreach Sprungbefehle in Perl

## Schleifen mit while/until

Mit Hilfe von while-Schleifen können Sie Programmanweisungen solange wiederholen, wie die Bedingung, die in der Schleife formuliert wird, erfüllt ist. Mit until-Schleifen können Sie Programmanweisungen wiederholen, bis die Bedingung, die in der Schleife formuliert wird, erfüllt ist.

### Beispiel 1:

    #!/usr/bin/perl

    $i = 1;
    print "zuerst die Wurzeln von 1 bis 10...\n\n";
    while($i <= 10)
     {
      print "Die Wurzel von ", $i, " ist ", sqrt($i), "\n";
      $i++;
     }
    $i = 1;
    print "und jetzt die Quadratzahlen von 1 bis 10...\n\n";
    until($i > 10)
     {
      print "Das Quadrat von ", $i, " ist ", $i * $i, "\n";
      $i++;
     }

### Beispiel 2:

    #!/usr/bin/perl

    $AccessDatei = "../../docs/access.log";
    $Zugriffe = 0;
    $Erfolge = 0;
    open(DATEI, "<".$AccessDatei) || die "Datei nicht gefunden!\n";
     {
      while(<DATEI>)
       {
        if(/HTTP\/1.0" 200/)  # nach 'HTTP/1.0" 200' suchen (= erfolgreicher Zugriff)
         {
          $Erfolge++;
         }
        $Zugriffe++;
       }
     }
    print "Von ", $Zugriffe, " Zugriffen waren ", $Erfolge, " erfolgreich\n";

### Erläuterung:

Eine while-Schleife (wie im obigen Beispiel 1, erster Teil) beginnt mit dem Wort `while` (while = solange). Dahinter folgt, in Klammern stehend, die Bedingung. Um eine Bedingung zu formulieren, brauchen Sie in der Regel Vergleichsoperatoren. Der Inhalt der Schleife wird solange wiederholt, wie die Schleifenbedingung wahr ist.

Eine until-Schleife (wie im obigen Beispiel 1, zweiter Teil) beginnt mit dem Wort `until` (until = bis). Dabei handelt es sich um eine andere logische Formulierung als bei `while`. Der Inhalt der Schleife wird solange wiederholt, bis die Schleifenbedingung wahr ist. Ansonsten gelten für until-Schleifen die gleichen Regeln wie für while-Schleifen. Achten Sie jedoch auf eine genaue logische Formulierung der Schleifenbedingung! So bedeuten im Beispiel die Schleifenbedingungen `while($i <= 10)` und `until($i > 10)` genau das gleiche.

Das obige Beispiel 2 zeigt einen speziellen, Perl-typischen Anwendungsfall der Schleife mit `while`. In dem Beispiel wird eine Datei zeilenweise eingelesen. Es handelt sich um eine Log-Datei, wie sie ein WWW-Server zum Protokollieren der Zugriffe erzeugt. In diesem speziellen Fall ist für die Schleifenbedingung kein Vergleichsoperator nötig. Die Schleife bricht automatisch ab, wenn alle Zeilen der Datei gelesen wurden (zu diesem Beispiel siehe auch Dateien lesen und schreiben sowie für das Suchen nach Zeichenketten den Abschnitt Reguläre Ausdrücke).

Notieren Sie Anweisungen innerhalb der Schleifen immer in geschweiften Klammern `{` und `}`, auch wenn es nur eine einzige Anweisung ist.

### Beachten Sie:

Achten Sie bei Schleifen mit Vergleichsoperatoren in der Schleifenbedingung immer darauf, daß es mindestens eine Möglichkeit gibt, um die Schleife nach einer angemessenen Zeit zu beenden. Andernfalls erzeugen Sie eine sogenannte "Endlosschleife", die zu Systemabstürzen führen kann!

Um Endlosschleifen zu vermeiden, brauchen Sie irgendetwas, das irgendwann zu einem Ausweg aus der Schleife führt. Meistens werden zu diesem Zweck sogenannte "Zähler" definiert, im Beispiel 1 etwa der Skalar `$i`. Dieser Skalar hat im Beispiel einen Anfangswert von 1 und wird innerhalb der Schleife bei jedem Durchgang mit der Anweisung `$i++;` um 1 erhöht, so daß die Schleifenbedingung irgendwann erreicht wird.

Eine andere Möglichkeit, Schleifen zu kontrollieren und abzubrechen, bieten die Sprungbefehle.

## Schleifen mit do..while/until

Bei dieser Art von Schleife wird nicht zuerst die Schleifenbedingung ausgewertet und davon abhängig der Anweisungsblock innerhalb der Schleife ausgeführt, sondern es wird zuerst der Anweisungsblock ausgeführt, und anschließend wird erst die Schleifenbedingung ausgewertet. Die Schleife wird also in jedem Fall mindestens einmal durchlaufen, egal wie die Schleifenbedingung lautet. Das kann sinnvoll sein, wenn Sie in der Schleifenbedingung mit Variablen arbeiten, deren genauen Wert Sie zum Zeitpunkt des Schleifenbeginns nicht kennen.

### Beispiel 1:

    #!/usr/bin/perl

    $Name = "Stefan";
    do
     {
      print $Name, "\n";
      $Name = "Virtuella";
     }
    while($Name ne "Virtuella")

### Beispiel 2:

    #!/usr/bin/perl

    $Name = "Stefan";
    do
     {
      print $Name, "\n";
      $Name = "Virtuella";
     }
    until($Name eq "Virtuella")

### Erläuterung:

Eine Schleife dieses Typs beginnt mit dem Schlüsselwort `do`. Anschließend folgt der Anweisungsblock der Schleife, wie üblich markiert durch geschweifte Klammern `{` bzw. `}`. Nach der schließenden geschweiften Klammer folgt die Schleifenbedingung. Die Schleifenbedingung können Sie mit `while` (solange) oder mit `until` (bis) formulieren. Dabei gelten die gleichen Regeln wie bei Schleifen mit while/until.

### Beachten Sie:

Achten Sie auch bei do..while/until-Schleifen darauf, daß keine Endlosschleifen entstehen. Die beiden obigen Beispiele bewirken jeweils das gleiche, nämlich die einmalige Ausgabe des Namens "Stefan". Beide Beispiele unterscheiden sich nur durch die unterschiedlich formulierte Schleifenbedingung. Wenn Sie in diesen beiden Beispielen die Vergleichsoperatoren `eq` und `ne` umgekehrt einsetzen würden, würde in beiden Fällen eine Endlosschleife entstehen!

## Schleifen mit for/foreach

Schleifen mit `for` oder `foreach` unterscheiden sich von Schleifen mit `while` oder `tuntil` dadurch, daß sie bereits in der Schleifenbedingung eine feste Abbruchbedingung vorsehen. Solche Schleifen eignen sich deshalb vor allem für Fälle, in denen "Anfangswert" und "Endwert" von vorneherein feststehen.

### Beispiel 1:

    #!/usr/bin/perl

    for($i=0;$i<=255;$i++)
     {
      printf("%4d = %2X",$i, $i);
      if($i % 8 == 0)
       { print "\n"; }
     }

### Beispiel 2:

    #!/usr/bin/perl

    @Alphabet = (A..Z);
    for(@Alphabet)
     {
      print $_, " ist der ", $i+1, ". Buchstabe im Alphabet\n";
      $i++;
     }

### Beispiel 3:

    #!/usr/bin/perl

    foreach $i (1..100)
     {
      next if $i % 2 == 0;
      print $i, "\n" if $i % 3 == 0;
     }

### Erläuterung:

Eine for-Schleife beginnt mit dem Wort `for`. Dahinter wird, in Klammern stehend, die Schleifenbedingung formuliert. Bei der "klassischen", C-konformen for-Schleife werden innerhalb der Schleifenbedingung drei Anweisungen notiert. In der ersten Anweisung wird ein Schleifenzähler definiert und initialisiert. Im obigen Beispiel 1 wird ein Zähler `$i` definiert und mit dem Wert 0 initialisiert. Die zweite Anweisung enthält die Bedingung, ab der die Schleife beendet wird. Dazu brauchen Sie Vergleichsoperatoren. In der dritten Anweisung wird der Schleifenzähler so verändert, daß er irgendwann die in der zweiten Anweisung notierte Bedingung erfüllt. Im Beispiel wird `$i` bei jedem Schleifendurchgang um 1 erhöht, so daß der Wert irgendwann größer 255 ist und damit die Bedingung der zweiten Anweisung erfüllt.
Das Beispiel 1 benutzt den Schleifenzähler, um bei jedem Schleifendurchgang die umgerechnete Hexadezimalzahl zum aktuellen Wert von $i auszugeben. Die Abfrage `if($i % 8 == 0)` enthält eine Modulodivision und bewirkt, daß nach 8 Ausgaben eine neue Zeile bei der Ausgabe begonnen wird. Die Ausgabe selbst erfolgt mit Hilfe der `printf`-Funktion (C-konform), die sauber formatierte Ausgaben auf die Standardausgabe erlaubt. Diese Funktion ist allerdings für CGI-Zwecke (also für Ausgaben in HTML-Form) nicht so sehr geeignet.

Das obige Beispiel 2 zeigt einen speziellen, Perl-typischen Anwendungsfall der for-Schleife. Diese Form ist sehr praktisch, um Elemente einer Liste oder eines Hashs der Reihe nach abzuarbeiten. Im Beispiel 2 wird eine Liste `@Alphabet` mit allen Großbuchstaben des Alphabets definiert. Mit der Anweisung `for(@Alphabet)` wird eine Schleife über diese Liste gelegt. Die Schleife wird automatisch so oft durchlaufen, wie die Liste Elemente hat. Um das jeweils aktuelle Listenelement anzusprechen, wird innerhalb der Schleife die vordefinierte Variable `$_` verwendet. In ihr ist der Inhalt des jeweils aktuellen Listenelements gespeichert.

Eine weitere Perl-typische Konstruktion ist eine Schleife mit `foreach`. Im obigen Beispiel 3 kommt eine solche Schleife zum Einsatz. Bei diesem Schleifentyp wird als Schleifenbedingung in Klammern ein eindeutiger Bereich definiert, z.B. (von Zahl..bis Zahl) oder Buchstaben (von Buchstabe..bis Buchstabe). Die Schleife wird automatisch so oft durchlaufen, bis alle Elemente innerhalb des definierten Bereichs abgearbeitet sind.
Wenn Sie einen Zähler innerhalb der Schleife für die gewünschte Prozedur einsetzen wollen, können Sie eine Zählervariable zwischen `foreach` und der Schleifenbedingung definieren, so wie in Beispiel 3 oben der Skalar `$i`.
Das obige Beispiel 3 gibt alle Zahlen zwischen 1 und 100 aus, die ungerade und durch 3 teilbar sind. Dabei hilft der Sprungbefehl `next`.

## Sprungbefehle in Perl

Perl wird nachgesagt, daß man damit nicht ordentlich strukturiert programmieren kann. Zwar stellt Perl mittlerweile alles zur Verfügung, was zu einem sauber strukturierten und sogar objektorientierten Programmieren gehört, doch Perl ist und bleibt eine Sprache für Scripts, bei denen sich Programmierer oft nicht die Mühe machen, den Programmablauf auf einzelne Unterprogramme zu verteilen. Eine häufig benutzte Alternative zu strukturierter Programmierung sind Sprungbefehle zu einer beliebigen anderen Stelle im Programm. Auch innerhalb von Schleifen sind Sprungbefehle sehr beliebt, um zum Beispiel den nächsten Schleifendurchlauf vorzeitig zu erzwingen, oder um eine Schleife abzubrechen.

### Beispiel 1:

    #!/usr/bin/perl

    # Raten Sie mal, welche Zahl $i am Ende als Ergebnis ausgibt

    $i = 1;
    goto Ergebnis;
    while($i < 1000)
     {
      ++$i;
      if($i % 3 == 0)
       {
        redo;
       }
      elsif($i % 7 == 0)
       {
        next;
       }
      elsif($i % 13 == 0)
       {
        last;
       }
      elsif($i % 17 == 0)
       {
        continue;
       }
     }
    Ergebnis:
    print "Ergebnis: ", $i;

### Beispiel 2:

    #!/usr/bin/perl

    while($i < 10)
     {
      ++$i;
      if($i % 2 != 0)
       {
        redo;
       }
     }
    continue
     {
       print $i, "\n";
     }

### Erläuterung:

Folgende Sprungbefehle stehen in Perl zur Verfügung:

`goto` springt zu einer beliebigen anderen Stelle im Programm. Dazu muß diese Stelle jedoch ein "Label" erhalten (vergleichbar mit einem Verweisanker innerhalb einer HTML-Datei). Ein Label definieren Sie, indem Sie einen Namen notieren und dahinter einen Doppelpunkt. Im obigen Beispiel wird in der vorletzten Zeile ein Label mit dem Namen `Ergebnis:` definiert. Mit einem `goto`-Befehl wie am Beginn des Beispiels können Sie zu einem solchen Label springen.

`redo` ist zur Verwendung innerhalb von Schleifen gedacht. Der aktuelle Schleifendurchgang wird abgebrochen. Der nächste Schleifendurchgang wird gestartet, allerdings ohne daß die Schleifenbedingung neu bewertet wird. Wenn Sie also beispielsweise einen Zähler in einer Schleifenbedingung hochzählen, wird die Schleife bei `redo` erneut durchlaufen, ohne daß der Zähler weiter hochgezählt wird.

`next` ist ebenfalls zur Verwendung innerhalb von Schleifen gedacht. Der aktuelle Schleifendurchgang wird abgebrochen. Der nächste Schleifendurchgang wird gestartet, und die Schleifenbedingung wird dabei ebenfalls ausgewertet.

`last` bricht eine Schleife sofort ab.

`continue` ist in Perl ein Spezialfall und anders zu behandeln als etwa in C. Das obige Beispiel 2 zeigt eine typische Verwendungsweise. `continue` leitet einen eigenen Anweisungsblock ein, genauso wie eine Schleife. Innerhalb dieses Anweisungsblocks, der wie üblich mit geschweiften Klammern `{` und `}` markiert wird, können Sie beliebige Anweisungen notieren. Wenn ein solcher `continue`-Block unmittelbar hinter einem Schleifenblock steht, wird er mit jedem Schleifendurchlauf mit durchlaufen. Mit einem Sprungbefehl wie `redo` innerhalb des Schleifenblocks können Sie verhindern, daß der `continue`-Block ausgeführt wird. Im obigen Beispiel 2 wird mit dieser Konstruktion erreicht, daß alle geraden Zahlen zwischen 1 und 10 ausgegeben werden.

weiter: | Operatoren
zurück: | Bedingte Anweisungen

SELFHTML/Quickbar CGI/Perl Perl-Sprachelemente

© 1998 Stefan Münz, muenz@csi.com