SELFHTML

Boucles

Page d'information: vue d'ensemble

vers le bas Boucles for
vers le bas Boucles foreach
vers le bas Boucles while
vers le bas Boucles do
vers le bas Boucles pour les hashes
vers le bas Récursivité

 vers le bas 

Boucles for

Ces boucles sont avant tout appropriées pour les cas dans lesquels on dispose d'une valeur de départ, d'une valeur de fin et d'un pas d'incrémentation, donc par exemple "pour tous les cas entre 1 et 100".

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";

for(my $i = 1; $i <= 100; $i++) {
 print "<span style=\"font-size:$i\pt\">$i pt</span><br>\n";
}

print "</body></html>\n";

Explication:

Le script envoie du code HTML au navigateur et sort du texte en tout 100 fois. Pour ce faire sont notées derrière le mot clé for, qui introduit une boucle for, entre parenthèses, trois petites instructions. La première instruction déclare la variable-compteur $i et l'initialise avec la valeur 1. La deuxième instruction est une condition. Elle exprime: "$i plus petit ou égal à 100". La troisième instruction incrémente de 1 la valeur actuelle de $i. La boucle sera maintenant exécutée aussi longtemps que la condition du milieu est remplie. Étant donné que dans l'exemple $i a d'abord pour valeur 1 et qu'ensuite à chaque exécution de la boucle grâce à $i++ il est incrémenté de 1, la boucle va être exécutée 100 fois au total. À la 101 ème fois. $i est plus grand que 100, la condition n'est plus remplie, et la boucle est terminée.

À la suite de la construction for suit un Autre page d'information bloc d'instructions, marqué comme d'habitude par des parenthèses accolades { et }. Entre elles peuvent être placées autant d'instructions que vous le souhaitez. Ces instructions vont être exécutées aussi souvent que la boucle est exécutée, dans l'exemple donc 100 fois. Dans l'exemple, du code HTML est créé avec print. Celui-ci contient dans un élément span une définition de format CSS pour la taille de police (font-size). Pour l'affectation à cette propriété CSS, la scalaire $i est utilisée. Ce qui aboutit dans l'exemple, à ce que le texte soit sorti 100 fois, et cela chaque fois avec une taille de police un peu plus grande. La première ligne sortie est seulement d'1 pt, donc d'une taille de 1 point, ce que personne pour ainsi dire ne pourra lire. Chaque ligne sortie est un point plus grande et la dernière est de 100 points ce qui suffit bien à remplir la fenêtre.

Pour formuler des conditions telles qu'elle figure dans la deuxième instruction dans la construction de la boucle for, vous avez besoin, soit de deux valeurs que vous voulez comparer, soit vous demandez directement si une expression figurant dans les parenthèses est vraie ou fausse. Dans l'exemple, deux valeurs sont comparées, à savoir la valeur de $i avec le nombre 100. Pour cela, vous avez besoin d'Autre page d'information Opérateurs de comparaison comme dans l'exemple l'opérateur plus petit que- <.

 vers le hautvers le bas 

Boucles foreach

Cette forme de boucle est spécialement conçue pour parcourir dans l'ordre l'un après l'autre les éléments d'une Autre page d'information liste ou Array (variables) . Une liste est ici examinée élément par élément. Vous pouvez en faire dépendre l'exécution d'instructions.

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";


my @biens = ("ma maison","ma voiture","mon bateau");
foreach (@biens) {
 print "$_<br>\n";
}

my @faiblesses = ("nicotine","alcool","le sexe faible");
my $faiblesse;
foreach $faiblesse (@faiblesses) {
 print "$faiblesse<br>\n";
}

print "</body></html>\n";

Explication:

L'exemple montre deux variantes différant légèrement de la façon d'utiliser la boucle foreach. Dans les deux cas un tableau est déclaré et des valeurs de départ lui sont affectées, d'une part @biens et d'autre part @faiblesses. Derrière le mot clé foreach est simplement mentionné entre guillemets le tableau. Dans le bloc d'instructions qui suit derrière dans les parenthèses accolades, peuvent figurer autant d'instructions que vous le désirez.

Dans le premier des exemples ci-dessus, est utilisée la Autre page d'information variable prédéfinie $_. Elle sauvegarde toujours la valeur actuelle du bloc d'instructions d'une boucle foreach, ce qui dans ce cas est l'élément respectivement actuel du tableau @biens.

Dans le deuxième exemple est utilisé à la place de $_ une scalaire distincte nommée $faiblesse. Si une telle scalaire est notée entre le mot clé foreach et la parenthèse avec le tableau, la valeur actuelle du bloc d'instructions de la boucle foreach, ce qui dans ce cas est l'élément respectivement actuel du tableau @faiblesses est sauvegardé dans cette scalaire.

Attention:

Les mots clés for et foreach possèdent certes un arrière plan sémantique différent mais peuvent être échangés l'un contre l'autre sur un plan syntaxique. Perl reconnaît lui-même le type de boucle que vous voulez utiliser. Ainsi, vous pouvez également par exemple écrire ce qui suit:
for(1..1000) {
 print "mille fois touché\n";
}
Le code sort simplement 1000 fois le texte, bien qu'il s'agisse en principe d'une boucle foreach, qui travaille la liste des nombres de 1 à 1000.

 vers le hautvers le bas 

Boucles while

Ce genre de boucle est approprié quand vous ne savez pas auparavant combien de fois la boucle doit être exécutée. Vous formulez simplement une condition et la boucle sera exécutée aussi souvent que la condition est remplie. Vous devez veiller vous même dans le bloc d'instructions qui dépend de la boucle à ce que la condition soit fausse à un moment ou à un autre et que la boucle soit terminée.

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";

my $heure_debut = time();
my $heure_fin = $heure_debut + 1;
my $heure_actuelle = 0;
my $i = 0;

while ($heure_actuelle <= $heure_fin) {
 $heure_actuelle = time();
 print "exécuté $i fois<br>";
 $i++;
}

print "</body></html>\n";

Explication:

Le script recherche d'abord avec la fonction Perl Autre page d'information time l'heure et la date actuelle et sauvegarde le résultat dans la scalaire $heure_debut. Ici, c'est un nombre qui est sauvegardé, à savoir le nombre de secondes écoulées entre le 1/1/1970 0.00 heures et la date et l'heure actuelle. Ensuite, une scalaire $heure_fin est déclarée et se voit affecter une valeur supérieure de 1 à celle de $heure_debut. Deux autres scalaires $heure_actuelle et $i sont déclarées et initialisées avec 0.

La boucle est introduite par le mot-clé while. Dans les parenthèses, une condition est formulée. Dans l'exemple, il s'agit de la condition "$heure_actuelle plus petit ou égal à $heure_fin". Derrière la condition, dans des parenthèses accolades, suit un bloc d'instructions avec autant d'instructions que vous le souhaitez. Ces instructions sont exécutées aussi souvent que la boucle est parcourue et que la condition est encore remplie.

La condition de la boucle est d'abord remplie dans l'exemple étant donné que $heure_actuelle a été initialisé avec 0 et est donc assurément plus petit que $heure_fin. Dans la boucle cependant, $heure_actuelle reçoit une nouvelle valeur à l'appel de la fonction time, cette valeur est en toute logique au moins aussi haute que celle de $heure_debut. La boucle sera de ce fait exécutée aussi souvent qu'il est nécessaire pour que $heure_actuelle, par l'appel de time, se voie affecter une valeur plus élevée que $heure_fin. Alors la boucle est terminée. Quand ce sera le cas, vous ne pouvez naturellement pas le prévoir, c'est dans cette mesure que la boucle while est idéale ici.

En outre une variable-compteur $i est encore incrémentée de 1 à chaque passage avec $i++. La valeur de $i est sortie à chaque fois. Dans la fenêtre du navigateur appelant, il sera possible de voir à la fin, combien de fois la boucle a été parcourue.

 vers le hautvers le bas 

Boucles do

Avec les boucles while il peut arriver que les instructions qui en dépendent ne soient jamais exécutées, à savoir quand la condition de la boucle s'avère fausse dès le premier passage. Une boucle do veille à ce que les instructions soient absolument exécutées une fois, étant donné que la condition de la boucle n'est vérifiée qu'à la fin de la boucle.

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";

my $condition = "interruption";
my $quelque_chose;
do {
 $quelque_chose = $condition;
 print "Ici figure $quelque_chose";
} until ($quelque_chose eq $condition);

print "</body></html>\n";

Explication:

L'exemple présente la façon typique de fonctionner d'une telle boucle. Dans un premier temps, une scalaire $condition se voit affecter une valeur initiale interruption. Une autre scalaire nommée $quelque_chose est déclarée sans recevoir de valeur. La boucle est introduite par do. Derrière duit un bloc d'instructions dans des parenthèses accolades, qui peut contenir autant d'instructions que vous le souhaitez. Dans l'exemple, la valeur de $condition, à savoir interruption est tout de suite dès le début affectée à la scalaire $quelque_chose. Ensuite ce contenu est sorti pour contrôle. Après la parenthèse accolade de fermeture qui met fin au bloc d'instructions, le mot until est noté suivi entre parenthèses de la condition proprement dite. Dans l'exemple, il est vérifié si $quelque_chose et $condition sont égaux, donc s'ils ont le même contenu. Étant donné que ce contenu a bien été affecté dans la boucle, la condition de la boucle est donc remplie. Ce qui fait que la boucle est interrompue. Car until est à comprendre comme "aussi longtemps que". À l'inverse de la boucle while dont le bloc d'instructions est exécuté aussi longtemps que la condition est vraie, le bloc d'instructions est ici exécuté jusqu'à ce que la condition soit vraie.

Dans l'exemple, la boucle est exécutée une fois bien que la condition de la boucle soit déjà vraie dès le premier passage. La raison est justement que le code qui dépend de la boucle est d'abord exécuté et qu'ensuite seulement la condition est vérifiée.

Attention:

Il existe également en Perl des boucles do pour lesquelles la condition n'est pas précédée de until, mais de while. Vous devez alors formuler la condition de la boucle négativement.

 vers le hautvers le bas 

Boucles pour les hashes

De la même façon que les tableaux peuvent parfaitement être "traversés", donc parcourus élément par élément avec les vers le haut boucles foreach, cette possibilité existe naturellement aussi pour les Autre page d'information Hashes. Étant donné qu'un élément de hash est toujours composé de deux valeurs dont la première est la clé et la deuxième la valeur proprement dite, un simple parcours comme avec foreach n'est pas possible. C'est pourquoi existe pour les hashes une syntaxe de boucle qui leur est propre.

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";

my %famille = (femme => "Jeanne", fille => "Fanny", fils => "Florian");
my $clef;
my $valeur;

while (($clef, $valeur) = each(%famille)) {
  print "$clef correspond &agrave; $valeur<br>\n";
}

while ($clef = each(%famille)) {
  print "$clef correspond &agrave; $famille{$clef}<br>\n";
}

print "</body></html>\n";

Explication:

L'exemple déclare un hash nommé %famille et lui affecte trois paires clé-valeur. Ensuite deux scalaires $clef et $valeur sont déclarées, qui sont nécessaires dans la boucle. La boucle est formulée en tant que boucle while. À l'intérieur de la condition de la boucle, est appelée cependant la fonction Perl Autre page d'information each. Celle-ci donne au choix une liste avec deux éléments, à savoir la clé suivante et la valeur qui y correspond, ou bien - dans un contexte scalaire - seulement la clé suivante du hash transmis.

Le script en exemple montre les deux variantes. Dans la première variante, la liste est sauvegardée avec les deux éléments dans l'expression ($clef, $valeur). $clef contient la clé respectivement actuelle du hash, et $valeur la valeur de la donnée correspondante. Dans l'exemple, la boucle est parcourue trois fois et sort ces enregistrements sous la forme femme correspond à Jeanne.

Dans la deuxième variante la fonction each est appelée dans un contexte scalaire, étant donné que la valeur retournée n'est sauvegardée que dans $clef. L'instruction print formulée dans la boucle sort cependant la même chose que dans la première variante. Cette fois cependant, aucune variable $valeur n'est disponible. Par une construction comme $famille{$clef} il peut cependant être accédé à la valeur actuelle respective .

 vers le hautvers le bas 

Récursivité

La récursivité est un moyen auquel recourir quand les boucles ne suffisent plus. Un cas typique d'utilisation pour la récursivité est le parcours de structures arborescentes. En français: quand par exemple vous voulez lire toute une arborescence de répertoires sans en connaître la structure des fichiers et des répertoires, alors c'est un cas typique pour une application récursive. Pour la récursivité, un Autre page d'information sous-programme est défini dans lequel figure une instruction qui appelle à nouveau le sous-programme. Il s'ensuit un effet d'imbrication. La récursivité est de toutes façons pas tout à fait exempte de critique sur le plan informatique. C'est pourquoi elle doit être programmée proprement.

L'exemple suivant montre comment vous pouvez lire une structure de répertoires à partir d'un répertoire donné et pouvez sortir formaté en HTML le résultat au navigateur appelant. L'exemple, au demeurant, n'est pas tout à fait banal.

Exemple d'un script CGI complet:

#!/usr/bin/perl -w

use strict;
use CGI::Carp qw(fatalsToBrowser);

my $repertoire_depart = "/usr/local/web";
my @tous;
my $total_octets = 0;

print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Sortie du test</title>\n";
print "</head><body>\n";
print "<h1>Atborescence</h1>\n";
print "<pre>repertoire_depart: <b>$repertoire_depart</b></pre>\n";
print "<hr noshade size=\"1\"><pre>\n";

rechercher($repertoire_depart);
@tous = sort(@tous);
foreach (@tous) {
  print "$_\n";
}
print "</pre><hr noshade size=\"1\">\n";
print "<pre>En tout: [$total_octets octets]</pre>\n";
print "</body></html>\n";


sub rechercher {
  my $repertoire = shift;
  my $enregistrement;
  my $nom_chemin;
  my $enregistrement_HTML;
  my $octets;
  local *DH;

  unless (opendir(DH, $repertoire)) {
   return;
  }
  while (defined ($enregistrement = readdir(DH))) {
   next if($enregistrement eq "." or $enregistrement eq "..");
   $nom_chemin = $repertoire."/".$enregistrement;
   if( -d $nom_chemin) {
    $HTML_enregistrement = $repertoire."/".$enregistrement." [REPERTOIRE]";
   }
   else {
    $octets = -s $nom_chemin;
    $total_octets += $octets;
    $HTML_enregistrement = $repertoire."/".$enregistrement." [$octets octets]";
   }
   push(@tous, $HTML_enregistrement);
   rechercher($nom_chemin) if(-d $nom_chemin);
  }
 closedir(DH);
}

Explication:

Tout d'abord trois variables importantes sont déclarées: $repertoire_depart sauvegarde le répertoire à partir duquel la recherche doit être effectuée, @tous est la liste dans laquelle, par la suite, les éléments lus seront sauvegardés, et $total_octets recherche le nombre d'octets de tous les fichiers.

Ensuite commence la sortie en HTML au navigateur. Au dessous, figure l'instruction rechercher($repertoire_depart);. C'est un appel du sous-programme rechercher, qui est introduit un peu plus bas avec sub rechercher. Ce sous-programme est en même temps celui s'appelle lui même dans l'avant-dernière instruction du bloc d'instructions qu'il comprend, en provoquant ainsi la récursivité.

Avec l'instruction rechercher($repertoire_depart); a lieu la lecture complète de la structure des fichiers et des répertoires. Ensuite la liste est triée alphabétiquement avec la fonction sort pour être sortie dans le navigateur enregistrement par enregistrement avec une boucle foreach.

Le cœur du script est cependant le sous-programme rechercher. Y sont d'abord déclarées une série de variables de travail. Étant donné que le sous-programme se rappelle lui-même, la question se pose s'il ne s'ensuit pas une confusion avec les noms de variables. La réponse est non. Car chaque exécution du sous-programme crée une instance distincte du programme dans la mémoire de travail, et étant donné que les variables sont déclarées localement avec my, leur validité reste cantonnée à une instance.
Une exception évidente est formée par l'instruction local *DH, qui déclare localement le descripteur de répertoire DH. Étant donné que my ne peut pas être appliqué aux descripteurs de fichiers et de répertoires (ou plutôt aux Typeglobs), on a eu recours ici à cette solution, qui certes travaille quelque peu différemment en interne mais donne le résultat désiré. Une autre variante serait d'utiliser la Autre page d'information module standard Symbol et de se créer dans chaque instance du sous-programme un nouveau descripteur de répertoire. Si le procédé paraît plus "propre", ce n'est finalement pas le cas. Par ailleurs, la variante avec local est sensiblement plus rapide.
Les nombreuses instances du sous-programme pour beaucoup de répertoires impliquent aussi que toujours plus de mémoire de travail est nécessaire. C'est un inconvénient important de la récursivité. Les constructions avec de nombreux appels de sous-programmes à eux-mêmes en récursivité doivent être évités pour cette raison dans les scripts CGI qui peuvent être appelés souvent et plusieurs fois en même temps sur les serveurs Web publics.

Le sous-programme rechercher attend un nom de chemin qui lui est transmis. Avec $repertoire = shift; le nom de chemin transmis est sauvegardé dans la scalaire $repertoire (voir aussi à ce sujet la fonction Perl Autre page d'information shift). Ensuite le répertoire transmis est ouvert grâce à la fonction Autre page d'information opendir . Ses enregistrements sont lus dans une boucle while avec la fonction Autre page d'information readdir. Les deux enregistrements avec les valeurs . et .., qui figurent dans chaque répertoire et qui symbolisent le répertoire actuel ou le répertoire parent sont sautés avec la commande de saut Autre page d'information next. Autrement, la récursivité s'embrouillerait dans une boucle sans fin.

Avec l'Autre page d'information opérateurs de test fichier pour fichiers et répertoires -d dans if( -d $nom_chemin) il est demandé si l'enregistrement du répertoire respectivement actuel est à nouveau un répertoire, donc un sous répertoire. En fonction de cela un élément HTML pour la liste à sortir est préparé. Plus bas il est demandé encore une fois avec -d si l'enregistrement est un sous-répertoire, et selon la réponse, le sous-programme rechercher est à nouveau appelé avec le sous-répertoire.

Après que la structure des répertoires est traitée et que toutes les instances du sous-programme rechercher sont terminées, Cela continue dans la partie supérieure du script avec @tous = sort(@tous);.

 vers le haut
page suivante Autre page d'information Commandes de saut
page précédente Autre page d'information Instructions conditionnelles
 

© 2001 Stefan Münz / © 2003 Traduction Adresse électronique Serge François, 13405@free.fr
Adresse électronique selfhtml@fr.selfhtml.org