Sommaire Carte Index Recherche Nouvelles Archives Liens A propos
[Barre Superieure]
[Barre Inferieure]
Cet article est disponible en: English  Castellano  Deutsch  Francais  Nederlands  Turkce  

convert to palmConvert to GutenPalm
or to PalmDoc

[Photo of the Author]
par Guido Socher

L´auteur:

Guido est un fan de Linux de longue date et un passionné de Perl. Vous pouvez visiter sa home page Linux à www.oche.de/~bearix/g/.


Sommaire:

Perl partie III

[Illustration]

Résumé:

Perl partie I offrait une vue d'ensemble de Perl. Dans perl partie II nous écrivions notre premier programme. Dans la partie III nous allons regarder de plus près les tableaux de variables.



 

Tableaux de variables

Un tableau consiste en une liste de variables à laquelle vous accédez par un indice. Nous avons vu que les "variables normales", aussi nommées variables scalaires, commencent par un signe dollar ($). Les tableaux commencent par un signe @ même si les données d'un tableau sont composées de plusieurs variables scalaires. Vous devez donc écrire un signe dollar lorsque vous faites référence à un champ du tableau. Regardons un exemple:

!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
# on déclare un nouveau tableau:
my @myarray;
# on l'initialise avec quelques données:
@myarray=("data1","data2","data3");
# on accède au premier élément (indice 0):
print "Le premier élément de myarray est: $myarray[0]\n";
Vous remarquerez que nous écrivons @myarray lorsque nous nous référons à l'ensemble et $myarray[0] lorsque nous faisons référence à un élément. Les tableaux dans Perl commencent à l'indice 0. De nouveaux indices sont automatiquement crées dès que vous ajoutez des données. Au moment de la déclaration du tableau, vous n'avez pas besoin de connaître sa taille. Comme vous le voyez ci-dessus, vous pouvez initialiser un tableau avec des données en listant celles-ci séparées par des points virgules et entre parenthèses.
("data1","data2","data3")
est un tableau anonyme. Par conséquent vous pouvez écrire ("data1","data2","data3")[1]
pour obtenir le deuxième élément de ce tableau:
!/usr/bin/perl -w
print "Le deuxième élément est:"
print ("data1","data2","data3")[1];
print "\n"
 

Boucles sur les tableaux

La boucle foreach dans Perl, permet l'itération de tous les éléments d'un tableau. Elle fonctionne ainsi:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
my @myarray =("data1","data2","data3");
my $lvar;
my $i=0;
foreach $lvar (@myarray){
   print "le numéro de l'élément $i est $lvar\n";
   $i++;
}
Exécuter ce programme nous donne:
l'élément numéro 0 est data1
l'élément numéro 1 est data2
l'élément numéro 2 est data3
Foreach extrait chaque élément du tableau et l'intègre dans la variable de la boucle ($lvar dans l'exemple ci-dessus). Il est important de remarquer que les valeurs ne sont pas copiées du tableau dans la variable de la boucle. Au contraire, la variable de la boucle est une sorte de pointeur et le fait de la modifier modifie les éléments du tableau. Le programme suivant transforme tous les éléments du tableau en majuscules. Dans perl tr/a-z/A-Z/ est équivalent à la commande unix "tr". Dans ce cas, il transforme toutes les lettres en majuscules.
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
my @myarray =("data1","data2","data3");
my $lvar;
print "before:\n";
foreach $lvar (@myarray){
    print "$lvar\n";
    $lvar=~tr/a-z/A-Z/;
}
print "\nafter:\n";
foreach $lvar (@myarray){
    print "$lvar\n";
}
Lorsque vous lancez le programme vous constatez que @myarray ne contient plus que des majuscules dans la seconde boucle:
avant:
data1
data2
data3

après:
DATA1
DATA2
DATA3
 

La ligne de commande

Dans Perl II nous avons vu qu'une fonction &getopt peut être utilisée pour lire la ligne de commande et toutes ses options. &getopt est comme son équivalent en C. C'est une fonction de bibliothèque. Les valeurs de la ligne de commande dans Perl sont affectées à un tableau nommé @ARGV. &getopt récupère cet @ARGV et en évalue les éléments.
Au contraire du C, le contenu du premier élément du tableau n'est pas le nom du programme mais le premier argument de la ligne de commande. Si vous voulez connaître le nom du programme Perl, vous devez lire $0 mais ce n'est pas le sujet de cet article. Voici un programme exemple nommé addition. Il récupère deux nombres de la ligne de commande et les additionne:
> add 42 2
42 + 2 is:44
.... et voici le programme:
#!/usr/bin/perl -w
# vérifier que nous avons 2 arguments:
die "USAGE: add number1 number2\n" unless ($ARGV[1]);
print "$ARGV[0] + $ARGV[1] is:", $ARGV[0] + $ARGV[1] ,"\n";
 

Une pile

Perl possède certaines fonctions internes qui utilisent un tableau de variables comme pile. Le programme suivant ajoute deux éléments à un tableau existant:
#!/usr/bin/perl -w
my @myarray =("data1","data2","data3");
my $lvar;
print "the array:\n";
foreach $lvar (@myarray){
    print "$lvar\n";
}
push(@myarray,"a");
push(@myarray,"b");
print "\nafter adding \"a\" and \"b\":\n";
while (@myarray){
    print pop(@myarray),"\n";
}
Pop supprime les éléments à la fin du tableau et la boucle while se poursuit jusqu'à ce que le tableau soit vide.  

Lire des répertoires

Perl offre les fonctions opendir, readdir et closedir pour lire le contenu d'un répertoire. readdir renvoie un tableau contenant tous les noms de fichier. En utilisant une boucle foreach vous pouvez parcourir tous les noms de fichier et rechercher un nom donné. Voici un simple programme qui recherche un nom de fichier donné dans le répertoire courant:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
die "Usage: search_in_curr_dir filename\n" unless($ARGV[0]);
opendir(DIRHANDLE,".")||die "ERROR: impossible de lire le répertoire courant\n";
foreach (readdir(DIRHANDLE)){
    print"\n";
    print "found $_\n" if (/$ARGV[0]/io);
}
closedir DIRHANDLE;
Regardons le programme. D'abord nous vérifions que l'utilisateur a fourni un argument à la ligne de commande. Dans la négative nous affichons un message d'utilisation et quittons le programme. Ensuite nous ouvrons le répertoire courant ("."). opendir est équivalent aux fonctions d'ouverture des fichiers. Le premier argument est un handle que vous devez passer aux fonctions readdir et closedir. Le deuxième argument est le chemin du répertoire.
Vient ensuite la boucle foreach. La première chose intéressante est que la variable de la boucle est manquante. Dans ce cas Perl fait de la magie en créant pour vous une variable nommée $_ qui est alors utilisée comme variable de la boucle. readdir(DIRHANDLE) renvoie un tableau et nous utilisons foreach pour voir chaque élément. /$ARGV[0]/io compare les expressions régulières contenues dans $ARGV[0] par rapport à la variable $_. io signifie que la recherche ne tient pas compte de la casse et compile une seule fois les expressions régulières. La dernière chose est une optimisation accélérant le programme. Vous pouvez l'utiliser si vous avez une variable dans une expression régulière et si vous êtes certains qu'elle ne changera pas à l'exécution.
Essayons. En supposant que nous ayons les fichiers article.html, array1.txt et array2.txt dans le répertoire courant, si nous cherchons "HTML" le programme affichera:
>search_in_curr_dir HTML
.
..
article.html
found article.html
array1.txt
array2.txt
Comme vous le voyez, la fonction readdir a trouvé 2 fichiers supplémentaires. "." et "..". Ce sont les noms du répertoire courant et du précédent.  

Un outil pour la recherche de fichier

J'aimerais terminer cet article sur un programme plus complexe et utile. Il est censé être un programme de recherche de fichier. Nous l'appelons pff (perl file finder). Il fonctionne pratiquement comme le programme ci-dessus mais recherche également les sous-répertoires. Comment pouvons-nous créer un tel programme? Plus haut, nous avons du code qui lit le répertoire courant et y recherche des fichiers. Nous devons commencer par le répertoire courant mais si l'un des fichiers (sauf . et ..) est un autre répertoire nous devons également y faire une recherche. C'est un algorithme récursif type:
sub search_file_in_dir(){
  my $dir=shift;
  ...lit le répertoire $dir ....
  ...si un fichier est un autre répertoire
    alors on appelle &search_file_in_dir(ce fichier)....
}
Dans Perl vous pouvez vérifier qu'un fichier est bien un répertoire et non un lien symbolique en utilisant if (-d "$file" && ! -l "$dir/$_"){....}.
Nous avons maintenant toutes les fonctionnalités requises et nous pouvons écrire le code (pff.gz).
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
# written by: guido socher, copyright: GPL
#
&help unless($ARGV[0]);
&help if ($ARGV[0] eq "-h");

# commence dans le répertoire courant:
search_file_in_dir(".");
#-----------------------
sub help{
    print "pff -- perl regexp file finder
USAGE: pff [-h] regexp

pff recherche dans le répertoire courant et ses sous-répertoires
des fichiers correspondants à une expression régulière donnée.
La recherche ne tient jamais compte de la casse.

EXEMPLE:
recherche d'un fichier contenant la chaîne foo:
    pff foo
recherche d'un fichier se terminant par .html:
    pff \'\\.html\'
recherche d'un fichier commençant par la lettre \"a\":
    pff \'^a\'
recherche d'un fichier contenant le nom articlehtml:
    pff \'article.*html\'
    remarquez le .* au lieu de seulement *
\n";
    exit(0);
}
#-----------------------
sub search_file_in_dir(){
    my $dir=shift;
    my @flist;
    if (opendir(DIRH,"$dir")){
        @flist=readdir(DIRH);
        closedir DIRH;
        foreach (@flist){
            # ignorer . et .. :
            next if ($_ eq "." || $_ eq "..");
            if (/$ARGV[0]/io){
                print "$dir/$_\n";
            }
            search_file_in_dir("$dir/$_") if (-d "$dir/$_" && ! -l "$dir/$_");
        }
    }else{
        print "ERROR: impossible de lire le répertoire $dir\n";
    }
}
#-----------------------
Regardons un peu le programme. Nous vérifions d'abord que l'utilisateur a fourni un argument à la ligne de commande. Si c'est non, c'est une erreur et nous affichons un petit texte d'aide. Nous affichons aussi un texte d'aide si l'option -h est donnée. Autrement, nous commençons la recherche dans le répertoire courant. Nous utilisons l'algorithme récursif comme décrit plus haut. Nous lisons le répertoire, recherchons les fichiers, vérifions si un fichier est un répertoire, si oui nous rappelons search_file_in_dir().

Dans la partie où nous vérifions s'il s'agit de répertoires nous vérifions aussi qu'il ne s'agit pas d'un lien vers un répertoire. Nous devons le faire parce que quelqu'un peut avoir crée un lien symbolique vers "..". Un tel lien forcerait le programme à s'exécuter indéfiniment si nous ne faisions pas cette vérification.

Nous n'avons pas encore parlé du next if ($_ eq "." || $_ eq ".."); . L'opérateur "eq" est l'opérateur de comparaison de chaîne de Perl. Ici, nous testons si le contenu de la variable $_ est équivalent à ".." ou ".". S'il est équivalent alors "next" est exécuté. "next"dans une boucle foreach signifie redémarrer au début de la boucle avec l'élément suivant du tableau. Il est similaire au "continue" du C.  

Références

Voici une liste d'autres intéressants tutoriels perl  

Discussion sur cet article

Chaque article possède sa page de discussion. Vous pouvez y soumettre un commentaire ou lire ceux d´autres lecteurs:
 page de discussion 

Site Web maintenu par l´équipe d´édition LinuxFocus
© Guido Socher, FDL
LinuxFocus.org

Cliquez ici pour signaler une erreur ou envoyer un commentaire à Linuxfocus
Translation information:
en -> -- Guido Socher
en -> fr Georges Tarbouriech

2001-03-18, generated by lfparser version 2.8