Perl partie III
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:
.... 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.
- push ajoute un élément à la fin du tableau
- pop lit un élément à la fin du tableau
- shift lit un élément au début du tableau
- unshift ajoute un élément au début du tableau
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:
2001-03-18, generated by lfparser version 2.8