par Guido Socher L´auteur: Guido est un fan de Linux de longue date et un passionn� de Perl. Ces derniers temps il est tr�s occup� � r�nover sa maison et � planter salades et autres trucs dans le jardin. Sommaire: |
Résumé:
Perl partie II est le premier article de notre s�rie Perl dans lequel nous allons r�ellement traiter d'un programme utile. Perl partie I offrait une vue d'ensemble de Perl.
Perl est id�al pour �crire de petits programmes, specialis�s dans une t�che. Pour acc�l�rer le processus de d�veloppement c'est une bonne id�e d'avoir un mod�le sous la main qui offre une structure et des fonctionnalit�s de base que vous aimeriez retrouver dans la plupart des programmes. Le code suivant offre une option d'analyse basique et poss�de d�j� une sous-routine pour afficher un message d'aide.
!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: # # supprimer le commentaire devant strict pour rendre # le compilateur plus rigoureux sur les d�clarations: #use strict; # global variables: use vars qw($opt_h); use Getopt::Std; # &getopts("h")||die "ERROR: Option inexistante. -h pour l'aide.n"; &help if ($opt_h); # #>>your code<< # #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- sub help{ print "help message\n"; exit; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- __END__ |
Observons le code. &getopts() lit les options de la ligne de commande.
Il d�finit les variables globales du nom $opt_<option> selon les options tap�es
sur la ligne de commande. Chaque option commence par un "-" (signe moins)
et doit suivre le nom du programme et pr�c�der tous les autres arguments.
La cha�ne de caract�res donn�e � getopts (le "h" dans le programme ci-dessus ) liste les lettres
de toutes les options autoris�es.
Si l'option r�cup�re un argument il faut ajouter deux-points (:) apr�s la lettre d'option
&getsopt("d:x:h") signifie que ce programme a les options -d, -x and -h.
Les options -d et -x re�oivent un argument. Ainsi "-o quelque chose" sera valide par contre
"-o -x n'importe quoi" provoque une erreur puisque le -o n'est pas suivi d'un argument.
Le &help if ($opt_h);
appelle la sous-routine help si l' option
-h a �t� donn�e sur la ligne de commande. Le sub help{
d�clare la
sous-routine. Pour l'instant, il n'est pas si important que vous compreniez chaque d�tail
du code. Prenez-le simplement comme un mod�le dans lequel vous ajouterez votre fonctionnalit�
principale.
Ecrivons un petit convertisseur de nombre qui utilise ce mod�le.
Le programme, que nous appellerons numconv, devrait convertir des nombres hexad�cimaux et d�cimaux.
numconv -x 30 devrait afficher l'�quivalent hexad�cimal du d�cimal 30.
numconv -d 1A devrait afficher l'�quivalent d�cimal de l'hexad�cimal 1A.
numconv -h devrait afficher un texte d'aide.
La fonction perl hex() convertit des nombres hexad�cimaux en d�cimaux et
la fonction printf() peut �tre utilis�e pour convertir des d�cimaux en hexad�cimaux.
Les ins�rer dans notre mod�le nous donne tr�s vite un programme sympathique:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: # # supprimer le commentaire devant strict pour rendre # le compilateur plus rigoureux sur les d�clarations: #use strict; # global variables: use vars qw($opt_d $opt_x $opt_h); use Getopt::Std; # &getopts("d:x:h")||die "ERROR: Option inexistante. -h pour l'aide.n"; &help if ($opt_h); if ($opt_d && $opt_x){ die "ERROR:les options -x et -d s'excluent mutuellement.\n"; } if ($opt_d){ printf("decimal: %d\n",hex($opt_d)); }elsif ($opt_x){ printf("hex: %X\n",$opt_x); }else{ # mauvaise utilisation -d ou -x doivent �tre pr�cis�s: &help; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- sub help{ print "convertit un nombre en hexad�cimal ou d�cimal. USAGE: numconv [-h] -d hexnum umconv [-h] -x decnum OPTIONS: -h pour l'aide EXAMPLE: numconv -d 1af \n"; exit; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- __END__ |
cliquez ici pour t�l�charger le code
du programme numconv figurant ci-dessus.
Dans les paragraphes suivants nous regarderons ce programme d'un peu plus pr�s
et nous essaierons de le comprendre.
Le branchement if dans perl se pr�sente sous 2 formes:
expr if (cond);
ou
if (cond) BLOCK [[elsif (cond) BLOCK ...] else BLOCK]
BLOCK est un nombre de conditions entre crochets {}. Cela signifie que vous pouvez
par exemple �crire:
printf("hello\n") if ($i);
if ($i == 2){ printf("i is 2\n"); }elsif ($i == 4){ printf("i is 4\n"); }else{ printf("i is neither 2 nor 4\n"); } |
Comme en C, il est �galement possible d'utiliser les op�rateurs && et ||.
printf("hello\n") if ($i);
Peut par cons�quent �tre �crit sous la forme
($i) && printf("hello\n");
Le || tel qu'utilis� dans notre mod�le traduit parfaitement les mots en langage parl�.
&getopts("d:x:h")||die "ERROR\n";
"Get the options or die". La fonction die() est �quivalente
� un printf suivi d'exit. Ainsi, il affiche un message et termine le programme.
&getopts("d:x:h")||die "ERROR\n";
est �quivalent �
die "ERROR\n"; if (! &getopts("d:x:h"));
O� le ! est un op�rateur logique not. Encore une fois ceci peut ausi �tre �crit sous la forme
die "ERROR\n"; unless (&getopts("d:x:h"));
unless est �quivalent � if-not et il est plus �l�gant � lire que if(!..)
Dans le premier article sur perl nous avons vu que les variables scalaires (les $-variables) �taient utilis�es sans les d�clarer. Elles se cr��ent au moment d'�tre utilis�es. C'est une caract�ristique int�ressante pour de petits programmes mais qui peut entra�ner des erreurs difficiles � trouver dans des programmes plus longs. D�clarer une variable donne au compilateur la possibilit� de faire des v�rifications compl�mentaires sur les fautes de frappe.
|
#!/usr/bin/perl
# $i=1; print "i is $tpyerr\n"; |
Ce code fonctionnera parfaitement dans perl et donnera "i is ". Le module perl "use strict;" peut forcer le compilateur � se plaindre d'un tel programme. Lorsque vous utilisez "strict" tout doit �tre d�clar� sinon c'est une erreur.
#!/usr/bin/perl
use strict; my $i=1; print "i is $tpyerr\n"; |
Ceci g�n�re le message suivant et rend la faute de frappe facile � trouver
Global symbol "$tpyerr" requires explicit package name at ./vardec line 4. Execution of ./vardec.txt aborted due to compilation errors. Exit 255
Maintenant il est facile de corriger le code du programme:
#!/usr/bin/perl
use strict; my $i=1; print "i is $i\n"; |
Les variables dans perl peuvent �tre d�clar�es en utilisant "my" ou,
comme nous l'avons d�j� vu dans le mod�le, "use vars":
use vars qw($opt_h);
Les variables globales sont d�clar�es par use vars. Ces
variables sont globales pour toutes les biblioth�ques incluses.
Les variables locales au fichier du programme en cours (globales parmi toutes les sous-routines de ce fichier)
sont d�clar�es par
my au d�but du programme (en dehors d'une sous-routine).
Les variables locales � la sous-routine en cours sont d�clar�es par
my � l'int�rieur de la sous-routine.
Les personnes exp�riment�es en programmation shell peuvent �tre tent�es de laisser de c�t� le signe $ en d�clarant la variable ou en lui attribuant une valeur. Ce n'est pas possible dans perl. Vous devez toujours �crire un signe $ lorsque vous utilisez une variable scalaire quoi que vous fassiez avec.
Vous pouvez aussi attribuer directement une valeur � la variable lorsque vous la d�clarez. my $myvar=10; d�clare la variable $myvar et d�finit sa valeur initiale � 10.
Nous avons d�j� utilis� la sous-routine "help" dans le programme numconv
ci-dessus. Les sous-routines peuvent �tre utilis�es pour programmer des fonctions personnalis�es.
Elles aident � structurer votre programme.
Une sous-routine peut �tre incluse n'importe o� dans le texte du programme
(avant ou apr�s qu'elle soit appel�e. Ca n'a pas d'importance).
Vous lancez une sous-routine par sub name(){... et vous l'appelez par
$retval=&name(...arguments...). La valeur retourn�e est la valeur de la derni�re commande
ex�cut�e dans la sous-routine. Les arguments donn�s � la sous-routine
sont pass�s au code � l'int�rieur de la sous-routine dans le tableau r�serv� @_.
Nous verrons cela plus en d�tail lorsque nous aborderons les tableaux de variables.
Pour l'instant, il suffit de savoir que les valeurs des variables scalaires
peuvent �tre lues dans la sous-routine en utilisant shift.
Voici un exemple:
#!/usr/bin/perl
use strict; my $result; my $b; my $a; $result=&add_and_duplicate(2,3); print "2*(2+3) is $result\n"; $b=5;$a=10; $result=&add_and_duplicate($a,$b); print "2*($a+$b) is $result\n"; # additionner deux nombres et les multiplier par 2: sub add_and_duplicate(){ my $locala=shift; my $localb=shift; ($localb+$locala)*2; } |
Maintenant que nous avons trait� une grosse partie de la syntaxe de perl
et des �l�ments du langage, il est temps d'�crire un vrai programme.
Perl a �t� con�u pour manipuler des fichiers texte avec tr�s peu d'effort de programmation.
Notre premier programme Perl doit comparer une liste d'abr�viations et trouver les doublons
dans cette liste. Par doublons nous entendons abr�viations apparaissant plusieurs fois dans la liste.
La liste ressemble � ce qui suit:
|
AC Access Class AC Air Conditioning AFC Automatic Frequency Control AFS Andrew File System ...
Vous pouvez t�l�charger la liste
ici. La syntaxe de ce fichier est la suivante:
Comment lire un tel fichier texte? Voici une partie du code perl pour lire le texte ligne par ligne:
.... open(FD,"abb.txt")||die "ERROR: can not read file abb.txt\n"; while( #do something } close FD; .... |
La fonction open prend un descripteur de fichier comme premier argument et
le nom du fichier � lire comme second argument. Les descripteurs de fichiers sont
une sorte de variables particuli�res. Il n'est pas n�cessaire de comprendre ce qu'est
r�ellement un descripteur de fichier. Vous le mettez simplement dans la fonction open,
vous l'utilisez dans la fonction qui lit les donn�es du fichier et pour finir
vous le renvoyez � la fonction close. La lecture du fichier est faite par <FD>.
Les <FD> peuvent �tre pass�s comme argument � une boucle while et le r�sultat est
une lecture ligne par ligne.
Traditionnellement les descripteurs de fichiers sont �crits en majuscules dans Perl.
O� vont nos donn�es? Perl poss�de un certain nombre de variables implicites. Ce
sont des variables que vous n'avez pas d�clar�es. Elles sont toujours pr�sentes.
Une telle variable est $_.
Cette variable contient la ligne lue � ce moment par la boucle while mentionn�e ci-dessus.
Essayons (t�l�charger le code):
#!/usr/bin/perl
use strict; my $i=0; open(FD,"abb.txt")||die "ERROR: can not read file abb.txt\n"; while(<FD>){ # incr�mente le compteur de ligne. Vous connaissez # sans doute le ++ du C: $i++; print "Line $i is $_"; } close FD; |
|
Vous remarquerez que nous n'avons PAS �crit print "Line $i is $_ \n". La variable $_ contient la ligne en cours du fichier texte ainsi que le caract�re nouvelle ligne (\n).
Maintenant, nous savons comment lire le fichier. Pour terminer vraiment notre programme nous devons apprendre encore 2 choses:
Expressions r�guli�res offre un moyen sophistiqu� de rechercher un mod�le dans une cha�ne de texte. Nous recherchons la premi�re cha�ne d'une ligne jusqu'au premier espace. En d'autres termes notre mod�le correspond � "d�but de ligne-->un nombre de caract�res sans espace-->un espace". Traduit en expressions r�guli�res de perl �a nous donne ^\S+\s. Si nous int�grons cela dans un m//; perl appliquera cette expression � la variable $_ (Rappel: cette variable contient la ligne courante; �a c'est bien). Le \S+ dans les expressions r�guli�res correspond � " un nombre de caract�res sans espace". Si nous mettons le \S+ entre parenth�ses nous r�cup�rons le "caract�re sans espace" dans la variable $1. Nous pouvons ajouter cela dans notre programme:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: # use strict; # global variables: use vars qw($opt_h); my $i=0; use Getopt::Std; # &getopts("h")||die "ERROR: No such option. -h for help.n"; &help if ($opt_h); # open(FD,"abb.txt")||die "ERROR: can not read file abb.txt\n"; while(<FD>){ $i++; if (m/^(\S+)\s/){ # $1 contient maintenant le premier mot (\S+) print "$1 est l' abr�viation de la ligne $i\n"; }else{ print "Ligne $i ne commence pas par une abr�viation\n"; } } close FD; # #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- sub help{ print "help text\n"; exit; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- __END__ |
L'op�rateur match (m/ /) retourne 1 si l'expression r�guli�re a �t� correctement appliqu�e � la ligne courante. Nous pouvons donc l'utiliser dans un branchement if. Vous devriez toujours utiliser un branchement if avant $1 (or $2, $3 ...) pour vous assurer que $1 contient vraiment des donn�es valides.
Nous pouvons maintenant lire le fichier et obtenir l'abr�viation, tout ce qui manque c'est un moyen de savoir si nous avons d�j� lu cette abr�viation. Ici nous avons besoin d'un nouveau type de donn�es perl: Les Tables de hachage. Les tables de hachage sont des tableaux de variables qui peuvent �tre index�s par une cha�ne de caract�res. Lorsque vous voulez la table de hachage compl�te vous �crivez dans perl un caract�re % devant le nom de la variable. Pour obtenir une seule valeur vous utilisez $variable_name{"index_string"}. Nous utilisons le m�me $ que pour les autres variables scalaires puisqu'un champ de la table de hachage n'est autre qu'une variable scalaire normale. Voici un exemple:
#!/usr/bin/perl -w
my %htab; my $index; # Chargement du tableau avec les donn�es: $htab{"something"}="valeur de something"; $htab{"somethingelse"}=42; # R�cup�ration des donn�es: $index="something"; print "%htab at index \"$index\" is $htab{$index}\n"; $index="somethingelse"; print "%htab at index \"$index\" is $htab{$index}\n"; |
A l'ex�cution du programme nous obtenons:
%htab at index "something" est la valeur de something %htab at index "somethingelse" est 42
Maintenant notre programme est complet:
1 #!/usr/bin/perl -w
2 # vim: set sw=4 ts=4 si et: 3 # 4 use strict; 5 # global variables: 6 use vars qw($opt_h); 7 my %htab; 8 use Getopt::Std; 9 # 10 &getopts("h")||die "ERROR: No such option. -h for help.n"; 11 &help if ($opt_h); 12 # 13 open(FD,"abb.txt")||die "ERROR: can not read file abb.txt\n"; 14 print "Abbreviations with several meanings in file abb.txt:\n"; 15 while(<FD>){ 16 if (m/^(\S+)\s/){ 17 # we use the first word as index to the hash: 18 if ($htab{$1}){ 19 # again this abbrev: 20 if ($htab{$1} eq "_repeated_"){ 21 print; # same as print "$_"; 22 }else{ 23 # this is the first duplicate we print first 24 # occurance of this abbreviation: 25 print $htab{$1}; 26 # print the abbreviation line that we are currently reading: 27 print; 28 # mark as repeated (= appears at least twice) 29 $htab{$1}="_repeated_"; 30 } 31 }else{ 32 # the first time we load the whole line: 33 $htab{$1}=$_; 34 } 35 } 36 } 37 close FD; 38 # 39 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 40 sub help{ 41 print "finddup -- Find abbreviations with several meanins in the 42 file abb.txt. The lines in this file must have the format: 43 abrev meaning 44 \n"; 45 exit; 46 } 47 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 48 __END__ |
Comment fonctionne-t-il? Nous lisons le fichier ligne par ligne et nous stockons les lignes dans notre table de hachage nomm�e %htab (ligne 33). L'index pour le hachage est l'abr�viation. Avant de charger la table de hachage nous v�rifions qu'il n'y a pas d�j� quelque chose de stock� dedans (ligne 18). S'il y a d�j� quelque chose dans la table nous avons 2 possibilit�s:
Il est probablement mieux de t�l�charger le code et de le tester.
Site Web maintenu par l´équipe d´édition LinuxFocus
© Guido Socher LinuxFocus 1999 |
Translation information:
|
1999-11-12, generated by lfparser version 0.7