Introduction ` a la programmation en Perl

— ou comment d´buter en Perl — e

Sylvain Lhullier Version 1.0.3 26 avril 2004

Introduction a la programmation en Perl `

c sylvain@lhullier.org

2

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Table des mati`res e
Licence Introduction 7 9

1 Premiers pas 11 1.1 Ex´cuter un programme en Perl . . . . . . . . . . . . . . . . . 11 e 1.2 Les types de donn´es . . . . . . . . . . . . . . . . . . . . . . . 13 e 1.3 La notion de contexte . . . . . . . . . . . . . . . . . . . . . . 14 2 Les 2.1 2.2 2.3 2.4 2.5 2.6 scalaires Les d´limiteurs de chaˆ e ınes de caract`res . . . e D´claration et utilisation des variables . . . . e La valeur undef . . . . . . . . . . . . . . . . . Op´rateurs, fonctions et contexte num´riques e e Op´rateurs, fonctions et contexte de chaˆ e ınes . Les op´rateurs de test . . . . . . . . . . . . . e 17 17 18 19 19 20 22

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

3 Structures de contrˆle o 25 3.1 Les instructions de test . . . . . . . . . . . . . . . . . . . . . 25 3.2 Les boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3 Un exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4 Listes et tableaux 4.1 Valeurs de listes . . . . . . . . . . . . . 4.2 Manipulation de tableaux . . . . . . . 4.3 Affectations . . . . . . . . . . . . . . . 4.4 Multi-d´claration . . . . . . . . . . . . e 4.5 Retour sur l’aplatissement des listes . 4.6 Absorption d’une liste par un tableau 4.7 La structure de boucle foreach . . . . 3 33 33 34 36 37 37 38 38

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

Introduction a la programmation en Perl ` 4.8 4.9

c sylvain@lhullier.org

Fonctions de manipulation de tableaux . . . . . . . . . . . . . L’op´rateur qw . . . . . . . . . . . . . . . . . . . . . . . . . . e

40 42 43 43 44 45 46 46 47 49 49 49 50 51 52 53 55 56 56 57 59 60 61 63

´ 5 Ecrire une fonction 5.1 D´claration . . . . . . . . . . . . . . . e 5.2 Appel . . . . . . . . . . . . . . . . . . 5.3 Visibilit´ des variables . . . . . . . . . e 5.4 Une liste pour valeur de retour . . . . 5.5 Premier exemple de fonction . . . . . . 5.6 Autre exemple : une fonction r´cursive e

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

6 Autres fonctions sur les listes 6.1 Joindre les ´l´ments dans une chaˆ avec join . . . . ee ıne 6.2 D´couper une chaˆ de caract`res en liste avec split e ıne e 6.3 Trier une liste avec sort . . . . . . . . . . . . . . . . . 6.4 S´lectionner des ´l´ments avec grep . . . . . . . . . . e ee 6.5 Appliquer un traitement a tous les ´l´ments avec map . ` ee ´ 6.6 Un exemple : le crible d’Eratosth`ne . . . . . . . . . . e 7 Tables de hachage 7.1 D´claration et initialisation . . . . e 7.2 Acc´der a un ´l´ment . . . . . . . e ` ee 7.3 Parcours . . . . . . . . . . . . . . . 7.4 Autovivification . . . . . . . . . . . 7.5 Existence et suppression d’une clef 7.6 Tables de hachage et listes . . . . . 7.7 Exemples . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

8 Tranches 67 8.1 Tranches de tableau . . . . . . . . . . . . . . . . . . . . . . . 67 8.2 Tranches de table de hachage . . . . . . . . . . . . . . . . . . 68 9 Manipulation des fichiers 9.1 Op´rateurs sur les noms de fichier . . . e 9.2 La fonction glob . . . . . . . . . . . . . 9.3 Premiers exemples . . . . . . . . . . . . 9.4 Ouverture de fichier . . . . . . . . . . . 9.5 Lecture, ´criture et fermeture de fichier e 9.6 Deuxi`me exemple . . . . . . . . . . . . e 9.7 Ex´cution de commandes avec open . . e 4 71 71 72 73 73 75 77 78

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

c sylvain@lhullier.org

Introduction a la programmation en Perl ` 78 81 81 82 83 84 85 86 86 87 87 87 89 89 90 91 94 94 96 97 98 99 101 101 103 104 106 107 109 110 113 115 117 119 122 122 123

9.8

´ Ecrire une table de hachage sur disque avec les fichiers DBM

10 Expressions r´guli`res e e 10.1 Fonctionnalit´s . . . . . . . . . . . . . . . . e 10.2 Bind . . . . . . . . . . . . . . . . . . . . . . 10.3 Caract`res . . . . . . . . . . . . . . . . . . . e 10.4 Ensembles . . . . . . . . . . . . . . . . . . . 10.5 Quantificateurs . . . . . . . . . . . . . . . . 10.6 Ensembles (suite) . . . . . . . . . . . . . . . 10.7 Regroupement . . . . . . . . . . . . . . . . 10.8 Alternatives . . . . . . . . . . . . . . . . . . 10.9 Assertions . . . . . . . . . . . . . . . . . . . 10.10R´f´rences arri`res . . . . . . . . . . . . . . ee e 10.11Variables d´finies . . . . . . . . . . . . . . . e 10.12Valeurs de retour de m// . . . . . . . . . . . 10.13Exemples de probl`mes . . . . . . . . . . . e 10.14Solutions des probl`mes . . . . . . . . . . . e 10.15Choisir son s´parateur . . . . . . . . . . . . e 10.16Options . . . . . . . . . . . . . . . . . . . . 10.17Quantificateurs non-gourmands . . . . . . . 10.18Substitution de variables dans les motifs . . 10.19Op´rateur tr . . . . . . . . . . . . . . . . . e 10.20Un dernier mot sur les expression r´guli`res e e 11 R´f´rences ee 11.1 R´f´rences sur scalaire . . . . . . . . . . . . ee 11.2 Utilisation des r´f´rences sur scalaire . . . . ee 11.3 R´f´rences sur tableau . . . . . . . . . . . . ee 11.4 R´f´rences sur table de hachage . . . . . . . ee 11.5 R´flexions a propos des r´f´rences . . . . . . e ` ee 11.6 R´f´rences anonymes vers scalaire . . . . . . ee 11.7 R´f´rences anonymes vers tableau . . . . . . ee 11.8 R´f´rences anonymes vers table de hachage ee 11.9 R´f´rences anonymes diverses . . . . . . . . ee 11.10L’op´rateur ref . . . . . . . . . . . . . . . . e 11.11R´f´rences circulaires . . . . . . . . . . . . . ee 11.12R´f´rences sur fichiers . . . . . . . . . . . . ee 11.13R´f´rences sur fonctions . . . . . . . . . . . ee 11.14Un dernier mot sur les r´f´rences . . . . . . ee 5

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

Introduction a la programmation en Perl `

c sylvain@lhullier.org

12 Utilisation de modules 125 12.1 Utilisation d’un premier module . . . . . . . . . . . . . . . . . 125 12.2 D’autres modules . . . . . . . . . . . . . . . . . . . . . . . . . 127 12.3 O` trouver les modules? . . . . . . . . . . . . . . . . . . . . . 127 u ´ 13 Ecrire un module 13.1 Premier exemple . . . . . . . . . . . 13.2 Et les variables? . . . . . . . . . . . 13.3 De la derni`re ligne d’un module . . e 13.4 R´pertoires . . . . . . . . . . . . . . e 13.5 Blocs BEGIN et END . . . . . . . . . . 13.6 Introduction a l’export de symboles . ` 13.7 Export par d´faut de symboles . . . e 13.8 Export individuel de symboles . . . . 13.9 Export par tags de symboles . . . . 13.10Exemple complet d’exports . . . . . 13.11Fonctions inaccessibles . . . . . . . . 13.12Documentation des modules . . . . . 13.13Un dernier mot sur les modules . . . 14 Programmation objet 14.1 Vous avez dit objet? . . . . . . 14.2 Pr´paratifs . . . . . . . . . . . e ´ 14.3 Ecrire un constructeur . . . . . 14.4 Appeler le constructeur . . . . 14.5 Manipulations de l’objet . . . . 14.6 Plusieurs constructeurs . . . . . ´ 14.7 Ecrire une m´thode . . . . . . . e 14.8 Reparlons des champs . . . . . 14.9 Composition . . . . . . . . . . 14.10Destruction d’un objet . . . . . 14.11H´ritage . . . . . . . . . . . . . e 14.12Classes d’un objet . . . . . . . 14.13Champs et m´thodes statiques e 14.14Exemple complet . . . . . . . . Conclusion L’auteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 129 130 131 132 133 134 135 135 136 137 138 139 142 143 143 144 144 146 147 149 150 152 153 156 157 160 161 163 169 171

6

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Licence
c 2002-2003 Sylvain Lhullier Version 1.0.3 26 avril 2004 Vous trouverez le derni`re version de ce document a cette adresse : e ` http://www.lhullier.org/publications/perl.html Ce document est y disponible en version HTML, PDF et sources DocBook. Permission est accord´e de copier, distribuer et/ou modifier ce document e selon les termes de la Licence de Documentation Libre GNU (GNU Free Documentation License), version 1.1 ou toute version ult´rieure publi´e par e e la Free Software Foundation. Pas de section inalt´rable. Pas de texte de e premi`re page de couverture. Pas de texte de derni`re page de couverture. e e Vous trouverez le texte officiel de la FDL a l’adresse : ` http://www.gnu.org/licenses/fdl.html Une traduction non-officielle en fran¸ais peut ˆtre lue a l’adresse : c e ` http://cesarx.free.fr/gfdlf.html

7

Introduction a la programmation en Perl `

c sylvain@lhullier.org

8

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Introduction
Voici un cours introductif a la programmation en Perl. Il est issu de la ` s´rie d’articles que j’ai ´crits pour GNU/Linux & Hurd Magazine France e e entre juillet 2002 et f´vrier 2003. e Ce langage tr`s riche et puissant est une boˆ a outils fort utile dans e ıte ` de nombreuses situations : administration syst`me, manipulation de textes e (mail, logs, linguistique, g´n´tique), programmation r´seau (CGI, mod_perl, e e e etc), bases de donn´es, interfaces graphiques etc. Ses nombreuses biblioth`e e ques le rendent vite irrempla¸able aux yeux de ceux qui en acqui`rent la c e maˆ ıtrise. La prise en main du langage est facilit´e par de nombreux rapproe chements possibles avec le C, le shell ou awk. Sa conformit´ POSIX en fait e un alli´ indispensable a l’administrateur syst`me. e ` e Ce document a la d´licate ambition de s’adresser a la fois au programe ` meur d´butant et a celui qui connaˆ e ` ıtrait bien le C ou le shell. Que le premier me pardonne de faire des comparaisons avec d’autres langages et de taire peut-ˆtre certains points qui me semblent ´vidents. Que le second m’excuse e e de passer a son goˆ t trop de temps a expliquer des notions qui lui semblent ` u ` simples ; les choses se corseront au fur et a mesure de la lecture ... ` Le d´but du document aborde des notions importantes en Perl et n´e e cessaires pour bien comprendre la suite. Vous serez sans doute un peu d´cu e¸ de ne pas faire des choses extrˆmement puissantes imm´diatement, mais e e patience : qui veut aller loin m´nage sa monture. e Pour vous mettre en app´tit, voici un petit exemple de la concision de e Perl et de sa puissance : my @r = qw(Un programme Perl est 5 fois plus rapide a ecrire); map { tr/A-Z/a-z/; s/\d//g; } @r; foreach (sort grep !/^$/, @r) { print "$_\n"; } Ce programme cr´´ une liste de mots (la phrase de la premi`re ligne), ee e transforme les majuscules de ces mots en minuscules, supprime les chiffres appartenant aux mots, supprime les mots vides et affiche la liste des mots 9

Introduction a la programmation en Perl `

c sylvain@lhullier.org

ainsi transform´s dans l’ordre lexical. Et dites-vous que vous aurez en main e toutes les notions n´cessaires avant la fin de la lecture du document ... e Perl est un langage de haut niveau, qui a la pr´tention de combiner les e avantages de plusieurs autres langages. Premi`re facilit´, il g`re lui mˆme la e e e e m´moire (ramasse-miettes, pas de limite de buffers, pas d’allocation a faire e ` etc). De plus, les tableaux, les listes et les tables de hachage sont natifs, ils sont int´gr´s a la grammaire mˆme du langage. R´cursivit´, modularit´, e e ` e e e e programmation objet, acc`s au syst`me et au r´seau, interface avec le C, e e e avec (g)Tk, avec Apache sont aussi au menu. Et souvenez-vous que l’une des devises de Perl est : there is more than one way to do it (il y a plus d’une fa¸on de le faire). c

10

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 1

Premiers pas
1.1 Ex´cuter un programme en Perl e

Il existe principalement deux types de langages : les langages compil´s e et les langages interpr´t´s. Pour les premiers (on retrouve par exemple dans ee cette cat´gorie le C et le C++), il existe deux phases distinctes : la come pilation des sources par un compilateur (gcc par exemple) puis l’ex´cution e du programme ainsi obtenu par le syst`me. Pour les seconds (les shells par e exemple), il n’y a pas de phase de compilation, un interpr´teur va lire le e code et directement agir en fonction de celui-ci. Perl est un langage a la fois interpr´t´ et compil´. Il n’y a pas de phase ` ee e interm´diaire de compilation car l’interpr´teur (qui se nomme perl en mie e nuscules, alors que le langage prend une majuscule) compile le code sans que le programmeur ne s’en rende compte, puis l’ex´cute. L’interpr´teur se e e charge donc a la fois de la compilation et de l’ex´cution. ` e Il existe trois fa¸ons distinctes de faire tourner un programme Perl : c • Mettre du code en ligne de commande. On peut ´crire ceci dans un e shell : perl -w -e ’print("Salut Larry\n");’ Le programme perl est lanc´ avec du code Perl comme argument, e directement sur la ligne de commande (option -e). En anglais, on appelle cela un one-liner (pas de traduction ´tablie en fran¸ais, peute c ˆtre monoligne, uniligne, soliligne ...). Le code sera alors ex´cut´ : la e e e fonction print affiche son argument. Salut Larry 11

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Ce n’est pas la fa¸on la plus courante d’´crire du Perl, mais c’est une c e mani`re facile et rapide de faire un petit calcul ou de faire appel a une e ` fonction Perl. L’option -w, que l’on retrouvera tout le temps, est positionn´e dans e le but que l’interpr´teur affiche des messages d’avertissement (ware nings) a diff´rents propos : il indique les variables utilis´es une seule ` e e fois ou utilis´es avant d’ˆtre initialis´es, il signale les red´finitions de e e e e fonctions, etc. Pour marquer les esprits, on pourrait faire un parall`le e avec l’option -Wall de gcc pour ceux qui connaissent. Je vous conseille donc de toujours utiliser cette option. • La seconde mani`re de faire est de cr´er un fichier salut.pl contenant : e e print("Salut Larry\n"); Puis de lancer la commande suivante depuis un shell : perl -w salut.pl Le programme perl est lanc´ avec le nom du fichier en argument. Il va e alors lire le contenu de ce fichier et l’interpr´ter comme du code Perl. e • La troisi`me fa¸on de faire est de cr´er un fichier salut2.pl contenant : e c e #!/usr/bin/perl -w print("Salut Larry\n"); La premi`re ligne est le shebang, bien connu des habitu´s des scripts e e en shell. Cette ligne (qui doit toujours ˆtre la premi`re du fichier) e e indique au syst`me d’exploitation le chemin de l’ex´cutable a lancer e e ` pour interpr´ter ce fichier. Le premier caract`re doit ˆtre un di`se, ce e e e e qui a pour effet que cette ligne est consid´r´e comme un commentaire ee Perl par l’interpr´teur. Ensuite un point d’exclamation. Puis le chemin e absolu vers l’ex´cutable perl (` adapter selon votre installation, voir e a ce que r´pond type perl ou which perl). Enfin les options que l’on e souhaite passer a l’interpr´teur. ` e Il faut maintenant rendre ce fichier ex´cutable et le lancer : e chmod +x salut2.pl ./salut2.pl Grˆce a la ligne de shebang, le syst`me le reconnaˆ donc comme a ` e ıt un programme n´cessitant un interpr´teur pour ˆtre ex´cut´. Cet ine e e e e terpr´teur est lanc´ avec pour param`tres les options fournies dans le e e e shebang ainsi que le nom du fichier. 12

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Cette derni`re fa¸on de faire est sans doute la plus courante d`s que e c e l’on ´crit un programme qui sera utilis´ plusieurs fois. e e Avant de continuer, quelques commentaires sur la syntaxe Perl. Except´ e dans les chaˆ ınes de caract`res, la pr´sence ou l’absence d’espaces, de sauts e e de ligne ou de tabulations ne change pas le comportement du programme, l’indentation est libre. Comme on vient de le voir, une instruction Perl est termin´e par un point-virgule. Les fonctions peuvent prendre leurs argue ments entre parenth`ses (comme en C) ; il faut aussi savoir que l’on peut se e passer de ces parenth`ses. On aurait pu ´crire : e e print "Salut Larry\n"; Les deux syntaxes sont tout a fait valides. Dans les cas simples (ap` pel d’une fonction avec un ou deux param`tres), on pourra omettre les e parenth`ses. Dans le cas de combinaisons plus complexes (plusieurs fonce tions appel´es en param`tre d’autres fonctions, listes en argument...), je e e vous conseille de les mettre pour lever toute ambigu¨ e possible. ıt´ Un commentaire commence par un di`se (#) et se termine en fin de ligne e (comme en shell). On constitue un bloc d’instructions en les regroupant dans des accolades {} comme en C. Des exemples suivront.

1.2

Les types de donn´es e

Perl est un langage faiblement typ´, ce qui signifie qu’une donn´e n’aura e e pas sp´cialement de type : les nombres, les chaˆ e ınes de caract`res, les bool´ens e e etc seront tous des scalaires et ne seront diff´renci´s que par leur valeur et e e par le contexte de leur utilisation. Il existe principalement trois structures de donn´es : les scalaires, les e tableaux et les tables de hachage. Chaque structure de donn´es est li´e a un e e ` caract`re sp´cial (lire la suite). e e Un scalaire est une donn´e atomique. Par exemple, ce pourrait ˆtre une e e chaˆ de caract`res (suite de caract`res) ou un nombre (entier ou flottant). ıne e e On verra plus tard que les r´f´rences (c’est-`-dire les pointeurs de Perl) sont ee a des scalaires, mˆme s’ils sont un peu sp´ciaux. Les variables scalaires sont e e pr´c´d´es d’un dollar ($) : $x est donc une variable scalaire. e e e Les tableaux permettent de stocker plusieurs scalaires en les indi¸ant. c De la mˆme fa¸on qu’en C, on pourra demander le i`me ´l´ment d’un tae c e ee bleau, i ´tant un entier. L’acc`s a un ´l´ment sera en temps constant, il ne e e ` ee d´pendra pas de son indice dans le tableau. Les variables de type tableau e 13

Introduction a la programmation en Perl `

c sylvain@lhullier.org

sont pr´c´d´es d’un arobase (@) : @t est donc une variable de type tableau. e e e Lorsque l’on utilise la syntaxe @t, on d´signe la totalit´ du tableau ; si nous e e voulons parler du i`me ´l´ment, nous allons manipuler un scalaire, il faudra e ee donc pr´fixer par un dollar : $t[4] est l’´l´ment d’indice 4 dans le tableau e ee @t, les crochets [] d´limitant l’indice (nul besoin de mettre l’arobase, Perl e sait grˆce aux crochets qu’il s’agit d’un ´l´ment de tableau). a ee Une table de hachage en Perl est une structure de donn´es permettant e d’associer une chaˆ de caract`res a un scalaire ; on parle de clefs et de ıne e ` valeurs : une valeur est associ´e a une clef. Naturellement, dans une mˆme e ` e table de hachage les clefs sont uniques ; les valeurs, par contre, peuvent ˆtre tout a fait quelconques. Les variables de type table de hachage sont e ` pr´c´d´es d’un caract`re pourcent (%) : %h est donc une variable de type e e e e table de hachage. De la mˆme fa¸on que pour les tableaux, %h repr´sente la e c e totalit´ de la table de hachage ; acc´der a un ´l´ment se fera avec un dollar : e e ` ee $h{uneclef} est l’´l´ment de clef uneclef de la table de hachage %h, les ee accolades {} d´limitant la clef. Fonctionnellement, on pourrait voir une table e de hachage comme un tableau dont les indices peuvent ˆtre non-num´riques. e e Nous reviendrons sur ces types de donn´es tout au long du document. e

1.3

La notion de contexte

Chaque op´ration en Perl est ´valu´e dans un contexte sp´cifique. La e e e e fa¸on dont l’op´ration se comportera peut d´pendre de ce contexte. Il peut c e e jouer un rˆle important sur le type des op´randes d’une expression et/ou sur o e le type de sa valeur. Il existe deux contextes principaux : le contexte scalaire et le contexte de liste. Par exemple, une affectation d’une expression a une variable de type ` scalaire ´valuera cette expression dans un contexte scalaire ; de la mˆme e e fa¸on, une affectation a une variable de type liste ´valuera le membre droit c ` e en contexte de liste. Autre exemple que je d´taillerai un peu plus loin, les e op´rateurs de test imposent un contexte pr´cis a leurs op´randes. e e ` e Certains op´rateurs et fonctions savent dans quel contexte ils sont ape pel´s et renvoient un scalaire ou une liste selon ce contexte d’appel. La e fonction grep en est un bon exemple (nous verrons cela lorsque nous parlerons des listes). On peut forcer le contexte d’une expression au contexte scalaire en utilisant l’op´rateur scalar(). e Il existe plusieurs contextes scalaires : le contexte de chaˆ ınes de caract`res, le contexte num´rique et le contexte tol´rant. Par exemple une e e e addition impose un contexte num´rique a ses deux op´randes ; cela signifie e ` e 14

c sylvain@lhullier.org

Introduction a la programmation en Perl `

que les op´randes sont transform´s en nombres quels que soient leur type e e et leur valeur (reste ensuite au programmeur a savoir ce que vaut une liste ` ou une chaˆ quelconque en contexte scalaire...). Le contexte de chaˆ ıne ınes est un contexte o` , comme son nom l’indique, les scalaires seront consid´r´s u ee comme des chaˆ ınes de caract`res. Le contexte tol´rant n’est ni de chaˆ e e ınes ni num´rique, il est simplement scalaire. e Il existe aussi un contexte vide (void context in english) qui correspond au fait que la valeur d’une expression est ignor´e. C’est par exemple le contexte e utilis´ lorsque l’on appelle une fonction sans r´cup´rer sa valeur de retour, e e e comme l’appel a la fonction print dans la section pr´c´dente. Ce contexte ` e e n’apporte pas grand chose au programmeur, mais permet a l’interpr´teur ` e Perl appel´ avec l’option -w de pr´venir en cas d’usage d’une expression e e sans effet de bord en contexte vide (c’est-`-dire une expression qui ne fait a rien et dont on ne se sert pas). Par exemple, la ligne d’instructions suivante : "Bonjour"; provoque le message suivant : Useless use of a constant in void context at prog.pl line 5. Vous aurez l’occasion de manipuler les contextes tout au long de cette introduction au langage. Mˆme si cela n’est pas forc´ment explicite a chaque e e ` instant, le contexte est souvent important.

15

Introduction a la programmation en Perl `

c sylvain@lhullier.org

16

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 2

Les scalaires
Les scalaires sont le type de donn´es atomique de Perl, dit autrement un e scalaire est une donn´e atome. Cela signifie que la granularit´ de donn´es e e e ne pas pas au del`. a Comme dit pr´c´demment, une variable scalaire peut contenir une chaˆ e e ıne de caract`res (String en Java et autres) ou un nombre (entier ou nome bre a virgule flottante : int ou float en C, C++ etc) ; je ne rentrerai ` pas dans l’explication de ce ”ou”. Voici des exemples de scalaires corrects : 12 "texte" ’texte’ -3.14 3e9 Contrairement au C o` le caract`re \0 de code ASCII 0 (z´ro) est le u e e marqueur de fin de chaˆ ıne, en Perl les chaˆ ınes de caract`res peuvent sans e souci contenir ce caract`re : "a\0f" est une chaˆ comportant 3 caract`res. e ıne e On aura donc aucun mal a traiter des fichiers binaires en Perl. `

2.1

Les d´limiteurs de chaˆ e ınes de caract`res e

Les chaˆ ınes de caract`res ont, comme en shell, principalement deux e d´limiteurs possibles : les doubles quotes (") et les simples quotes (’). Elles e n’ont pas le mˆme rˆle : e o • Dans une chaˆ d´limit´e par des doubles quotes, le contenu est inıne e e terpr´t´ : ee "Bonjour\n" est une chaˆ suivie d’une fin de ligne. De la mˆme ıne e mani`re "\t" est une tabulation (il existe d’autres caract`res sp´ciaux). e e e Dans "Bonjour $prenom" la variable $prenom est substitu´e par son e contenu ; c’est-`-dire que ce scalaire contiendra la chaˆ Bonjour, suia ıne vie d’une espace, suivie du contenu de la variable $prenom. 17

Introduction a la programmation en Perl `

c sylvain@lhullier.org

S’il faut accoler un texte imm´diatement apr`s une variable, on utilie e sera les accolades pour d´limiter le nom de la variable ; par exemple e dans "il ${prefixe}donn$suffixe", c’est bien la variable $prefixe qui sera utilis´e, puis la chaˆ donn et enfin la variable $suffixe. e ıne On notera que ces accolades n’ont rien a voir avec celles des tables de ` hachage. Certains caract`res doivent ˆtre ”prot´g´s” avec un anti-slash (\) si on e e e e veut les faire apparaˆ telsquels dans la chaˆ de caract`res ; ce sont ıtre ıne e les quatre suivants : " $ @ \. La chaˆ "\$v" ne contient donc pas la ıne valeur d’une suppos´e variable $v mais contient le caract`re dollar et e e le caract`re v. e • Dans une chaˆ d´limit´e par des simples quotes, aucune interpr´tation ıne e e e du contenu n’a lieu : ’Bonjour\n’ est une chaˆ comportant les caract`res B o n j o u r \ ıne e et n, c’est-`-dire 9 caract`res (notez que ’\n’ comporte 2 caract`res). a e e La chaˆ ’Bonjour $prenom’ ne comporte pas le contenu d’une hyıne poth´tique variable $prenom mais le caract`re dollar suivi de la chaˆ e e ıne prenom. Puisque les variables ne sont pas substitu´es, les caract`res a prot´ger e e ` e sont moins nombreux ; seuls ’ et \ ont besoin d’ˆtre pr´c´d´s d’un e e e e anti-slash pour apparaˆ tels-quels dans une chaˆ d´limit´e par de ıtre ıne e e simples quotes. Les nombres n’ont quant a eux pas besoin de d´limiteurs pour ˆtre ma` e e nipul´s : $x = 10.2 affecte le nombre 10,2 a la variable $x. e `

2.2

D´claration et utilisation des variables e

En Perl, il n’est pas obligatoire de d´clarer les variables. Par d´faut, e e l’usage d’une variable la cr´e ; si c’est un scalaire, elle aura la valeur undef e (lire plus loin) ; s’il s’agit d’une liste ou une table de hachage, elle sera vide. Pour d’´videntes raisons de relecture et pour ´viter des erreurs bˆtes, je e e e vous conseille de toujours d´clarer vos variables avant de les utiliser (sauf e peut-ˆtre dans le cas de scripts de quelques lignes). Pour d´clarer une vae e riable, il nous faut utiliser my : my $x; my $y = 10; my $z = "hello"; 18

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Nous venons ici de d´clarer trois variables scalaires. Ces variables seront e visibles (accessibles) dans toute la suite du bloc ainsi que dans les sous-blocs (comme en C) ; comme on s’y attend, elles ne le seront par contre pas dans les fonctions appel´es depuis ces blocs. Le placement des d´clarations est e e libre dans le bloc (comme en C++), il n’est pas n´cessaire de les mettre en e d´but de bloc. e Voici quelques exemples d’utilisation de variables (on suppose qu’elles sont d´j` d´clar´es) : ea e e $x = $y + 3; $prenom = "Jules"; $phrase = "Bonjour $prenom"; print("$phrase\n"); Cette derni`re ligne affichera a l’´cran Bonjour Jules suivi d’un cae ` e ract`re de nouvelle ligne. Les habitu´s du shell noterons bien qu’une vae e riable est toujours pr´c´d´e de son dollar mˆme si elle est a gauche d’un ´gal e e e e ` e d’affectation.

2.3

La valeur undef

C’est une valeur particuli`re signifiant ((non-d´fini)). C’est aussi la valeur e e par d´faut des variables scalaires non initialis´es : my $x; est ´quivalent a e e e ` my $x=undef; On peut affecter cette valeur a une variable apr`s son initia` e lisation : $x=undef; ou undef($x); Si l’on veut tester qu’une variable scalaire vaut ou non undef, il faut utiliser la fonction defined : if(defined($x))... Ce test est vrai si $x est d´finie, c’est-`-dire si elle ne vaut pas undef. Une erreur classique est e a d’´crire : *incorrect* if($x!=undef) *incorrect* Ne surtout pas tenter e de comparer une variable a undef, car cela ne fait pas ce qu’on attend. ` La valeur undef est une valeur fausse pour les tests. Le test if( $x ) ... est faux si $x est non-d´finie. Mais comme on le verra plus tard, il est e ´galement faux si $x vaut 0 (z´ro) ou bien la chaˆ vide. Donc un test e e ıne if( $x ) ... est potentiellement dangereux. Pour tester si une variable est d´finie, une seule bonne fa¸on : if(defined($x))... e c

2.4

Op´rateurs, fonctions et contexte num´riques e e

Sur les nombres, les op´rateurs classiques sont disponibles : + - / * % ; e ce dernier op´rateur % est le modulo, c’est-`-dire le reste de la division enti`re e a e 19

Introduction a la programmation en Perl `

c sylvain@lhullier.org

du premier op´rande par le second. Notez que la division effectu´e par l’op´e e e rateur / n’est pas une division enti`re mais une division r´elle, cela mˆme si e e e ses op´randes sont entiers (2/3 vaut 0.6666...) ; si vous voulez effectuer une e division enti`re, il vous faut tronquer le r´sultat de la division pr´c´dente e e e e avec int() : l’expression int($x/$y) vaut le quotient de la division enti`re e de $x par $y. Des raccourcis existent : += -= *= /= %=. Ces op´rateurs sont a la fois e ` une op´ration arithm´tique et une affectation : $x+=3 est ´quivalent a $x=$x+3 e e e ` mais en plus synth´tique : on ajoute 3 a $x. L’instruction $y*=5 multiplie e ` $y par 5. Il existe aussi des auto-incr´menteurs et des auto-d´cr´menteurs : ++ et e e e -- qui peuvent ˆtre plac´s avant ou apr`s une variable : ils ajoutent ou e e e d´duisent 1 a cette variable. $x++ a le mˆme effet que $x+=1 ou que $x=$x+1. e ` ` e L’op´rateur ** correspond a la puissance : 2**10 vaut 1024. e ` Les fonctions suivantes manipulent les nombres : • sin($x) cos($x) renvoient le sinus et le cosinus de $x. • exp($x) log($x) renvoient e puissance $x et le logarithme en base e de $x. • abs($x) renvoie la valeur absolue de $x. • sqrt($x) renvoie la racine carr´e de $x. e Voici quelques r`gles de conversion en contexte num´rique. Les chaˆ e e ınes de caract`res repr´sentant exactement un nombre sont converties sans probl`me ; e e e "30" + "12" vaut 42. Dans tous les autres cas (´num´r´s dans ce qui suit), e ee l’option -w provoquera un message d’avertissement. Les scalaires commen¸ant c par un nombre sont converties en ce nombre : "34.2blabla" vaudra 34,2. Les autres valeurs scalaires (y compris undef) sont converties en 0. Conclusion : utilisez toujours l’option -w !

2.5

Op´rateurs, fonctions et contexte de chaˆ e ınes

Les chaˆ ınes de caract`res ont aussi leurs op´rateurs. Le point (.) permet e e de concat´ner deux chaˆ : l’instruction $x="bon"."jour" a pour effet e ınes d’affecter la chaˆ ”bonjour” a $x (pas de gestion de la m´moire a effectuer). ıne ` e ` Cet op´rateur est, entre autres cas, utile lorsque certaines parties de la e chaˆ sont les valeurs de retour de fonctions ; en effet, il suffit souvent d’utiıne liser les substitutions effectu´es dans les chaˆ e ınes d´limit´es par des doubles e e quotes pour concat´ner deux chaˆ e ınes. 20

c sylvain@lhullier.org

Introduction a la programmation en Perl `

L’op´rateur x est la multiplication pour les chaˆ e ınes de caract`res : "bon"x3 e vaut "bonbonbon". Fort sympathique ... Les raccourcis suivant peuvent ˆtre utilis´s : .= x= L’expression $x.=$y e e est ´quivalente a $x=$x.$y et concat`ne donc $y a la fin de $x. e ` e ` Voici un certain nombre de fonctions utiles qui manipulent les chaˆ ınes de caract`res : e • length($x) renvoie la longueur de la chaˆ $x. Par exemple ıne length("bonjour\n") vaut 8 et length(’bonjour\n’) vaut 9. • chop($x) supprime le dernier caract`re de la chaˆ $x (la variable $x e ıne est modifi´e). Ce caract`re est renvoy´ par la fonction : $c = chop($l); e e e • chomp($x) supprime le dernier caract`re de $x s’il s’agit d’une fin e de ligne (la variable $x est modifi´e). Cette fonction peut prendre e plusieurs arguments, chacun subira un sort similaire. Ne pas ´crire e *incorrect* $x=chomp($x) *incorrect* car chomp renvoie le nombre de caract`res supprim´s. Cette fonction nous sera tr`s utile lorsque e e e nous lirons des fichiers ligne a ligne. ` • reverse($x) en contexte scalaire, renvoie la chaˆ compos´e des caıne e ract`res de $x dans l’ordre inverse. Par exemple e $v = reverse("bonjour\n") affecte "\nruojnob" a $v. On rencon` trera aussi cette fonction chez les listes (son comportement d´pend du e contexte). • substr($x,offset,length) vaut la sous-chaˆ de position offset et de ıne longueur length. Les positions commencent a 0 : ` substr("bonjour",1,2) vaut on. La longueur peut ˆtre omise, dans e ce cas toute la partie droite de la chaˆ est s´lectionn´e. ıne e e Cette fonction peut ˆtre une lvalue, c’est-`-dire qu’on peut lui affece a ter une valeur (lvalue pour left-value : a la gauche du signe ´gal de ` e l’affectation) : my $v = "salut toi"; substr($v,5,1) = "ation a "; ` $v vaut alors "salutation a toi". C’est l` que l’on se rend compte ` a que Perl g`re vraiment la m´moire tout seul ! e e • index($cha^ne,$sousCha^ne,$position) renvoie la position de la ı ı premi`re occurrence de $sousCha^ne dans $cha^ne. Le troisi`me pae ı ı e ram`tre, s’il est fourni, indique la position du d´but de la recherche ; e e sinon la recherche part du d´but de la chaˆ (position 0). e ıne 21

Introduction a la programmation en Perl `

c sylvain@lhullier.org

• rindex($cha^ne,$sousCha^ne,$position) effectue la mˆme recherı ı e che que la fonction index mais en partant de la fin de la chaˆ (la ıne recherche est effectu´e de droite a gauche). e ` En contexte de chaˆ de caract`res, undef vaut la chaˆ vide ; l’option ıne e ıne -w provoquera un message d’avertissement. Dans ce contexte, un nombre vaut la chaˆ de sa repr´sentation d´cimale. ıne e e

2.6

Les op´rateurs de test e

Les bool´ens (type de donn´es ayant pour seules valeurs vrai et faux) e e n’existent pas en tant que tels en Perl, on utilise les scalaires pour effectuer les test (comme C le fait avec les entiers). Il me faut donc pr´ciser quelles e sont les valeurs scalaires vraies et quelles sont les fausses. Les valeurs fausses sont : • 0, c’est-`-dire l’entier valant z´ro, a e • "0" ou ’0’, c’est-`-dire la chaˆ de caract`res ne comportant que le a ıne e caract`re z´ro (pas le caract`re \0 de code ASCII z´ro, mais 0 de code e e e e 48), • la chaˆ vide :"" ou ’’ (ce qui est la mˆme chose), ıne e • undef Toutes les autres valeurs sont vraies, par exemple : 1, -4.2, "blabla" etc. La plus originale est "00" qui vaut l’entier 0 dans les op´rations num´e e riques, mais qui est vraie ... Il existe deux cat´gories d’op´rateurs de test : ceux pour lesquels on ime e pose un contexte num´rique aux op´randes et ceux pour lesquels on ime e pose un contexte de chaˆ de caract`res. Par exemple == teste l’´galit´ de ıne e e e deux nombres (contexte num´rique) et eq teste l’´galit´ de deux chaˆ e e e ınes (contexte de chaˆ ıne). ("02"=="2") est vrai alors que ("02" eq "2") est faux. La diff´rence est encore plus flagrante pour les op´rateurs d’inf´riorit´ e e e e et de sup´riorit´ ; < teste l’ordre entre nombres, lt teste l’ordre ASCII entre e e chaˆ ; donc (9<12) est vrai alors que (9 lt 12) est faux car 9 est apr`s ınes e 1 dans la table ASCII. Confondre ou m´langer ces deux types d’op´rateurs e e est une erreur tr`s courante que font les d´butants, ainsi que les initi´s qui e e e ne font pas attention ... Sachez que l’option -w permet souvent de rep´rer e ces situations. 22

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Voici un tableau d´crivant les op´rateurs de tests : e e contexte impos´ e ´galit´ e e diff´rence e inf´riorit´ e e sup´riorit´ e e inf ou ´gal e sup ou ´gal e comparaison num´rique e == != < > <= >= <=> de chaˆ ınes eq ne lt gt le ge cmp

Les op´rateurs bool´ens classiques sont pr´sents : e e e • expr1&&expr2 est vrai si expr1 et expr2 sont vraies (si expr1 est faux expr2 n’est pas ´valu´e), e e • expr1||expr2 est vrai si expr1 ou expr2 est vraie (si expr1 est vrai expr2 n’est pas ´valu´e), e e • !expr est vrai si expr est fausse. Il existe aussi les op´rateurs and or et not. Ceux-ci ont la mˆme table e e de v´rit´ que les pr´c´dents, mais sont d’une priorit´ plus faible. e e e e e Les deux op´rateurs cit´s a la derni`re ligne du tableau ne sont pas des e e ` e op´rateurs de test mais des op´rateurs de comparaison ; ils sont pr´sents e e e dans ce tableau en raison des similitudes qu’ils ont avec les op´rateurs de e test en ce qui concerne le contexte impos´ aux op´randes. Ces op´rateurs e e e renvoient un nombre qui d´pend de l’ordre entre leurs deux param`tres. e e L’expression ($x<=>$y) est : • positive si $x est un nombre plus petit que $y, • n´gative si $x est un nombre plus grand que $y, e • nulle si $x et $y sont des nombres ´gaux. e Cet op´rateur <=> est surnomm´ spaceship (vaisseau spatial en fran¸ais) e e c en raison de sa forme ;-) ... Pour l’op´rateur cmp, la comparaison se fait e sur l’ordre des chaˆ ınes selon la table ASCII. Ces op´rateurs seront fort utiles e lorsque nous parlerons de la fonction sort qui effectue le tri des listes.

23

Introduction a la programmation en Perl `

c sylvain@lhullier.org

24

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 3

Structures de contrˆle o
Ici nous allons apprendre a contrˆler le flux des instructions en Perl. En ` o effet un programme n’est pas qu’une simple suite d’instructions se d´roulant e lin´airement une fois et une seule. e Il faut savoir que Perl (tout comme le C) permet d’indenter notre code comme bon nous semble, les exemples qui suivent comportent donc des choix personnels d’indentation qui peuvent diverger des vˆtres. o

3.1

Les instructions de test

Ces instructions permettent de conditionner l’ex´cution d’instructions a e ` la valeur de v´rit´ d’une expression. L’instruction la plus usit´e est le if (si e e e en fran¸ais) qui a besoin d’une expression et d’un bloc d’instructions. Cette c expression sera ´valu´e en contexte scalaire et servira de condition ; si elle e e est v´rifi´e, le bloc d’instructions sera ex´cut´. e e e e if( $x != 1 ) { print "$x\n"; } Ce code Perl a pour effet d’afficher la variable $x si elle ne vaut pas 1. Plusieurs instructions peuvent ˆtre plac´es dans le bloc, elles seront alors e e toutes ex´cut´es si la condition est vraie. Notez que les accolades ({}) sont e e obligatoires pour d´limiter le bloc (contrairement au C). e Il est possible d’ex´cuter d’autres instructions dans le cas o` la condition e u est fausse. On utilise pour cela l’op´rateur else (sinon en fran¸ais) qui, lui e c 25

Introduction a la programmation en Perl ` aussi, est suivi d’un bloc d’instructions : if( $x == $y ) { print "\$x et \$y sont egaux\n"; ´ } else { print "\$x et \$y sont diff´rents\n"; e }

c sylvain@lhullier.org

Le fait que les accolades sont obligatoires a pour cons´quence que le e programme suivant est incorrect : if( condition1 ) { instructions1 } else # Attention ce code est incorrect if { instructions2 } Il faut en effet entourer le second if par des accolades comme ceci : if( condition1 ) { instructions1 } else { if( condition2 ) { instructions2 } } Si le programmeur se sent des envies de devenir sylviculteur en plantant des forˆts d’ifs, il faudrait donc qu’il utilise de multiples couples d’accolades. e Pour ne pas rencontrer les mˆmes probl`mes que le Lisp en rencontre pour e e les parenth`ses ;-), Perl met a notre disposition l’instruction elsif qui e ` 26

c sylvain@lhullier.org

Introduction a la programmation en Perl `

permet de cumuler le comportement d’un else et d’un if tout en faisant l’´conomie d’un couple d’accolades : e if( condition1 ) { instructions1 } elsif( condition2 ) { instructions2 } else { instructions3 } L’instruction switch de C n’a pas d’´quivalent direct en Perl ; il faut e pour cela planter une forˆt d’ifs, comme dans l’exemple pr´c´dent. e e e Mais Perl n’en reste pas l`. Il existe une syntaxe tr`s utilis´e pour effeca e e tuer une unique instruction si une condition est v´rifi´e : e e instruction if( condition ); On parle ici de modificateur d’instruction. Pour cette syntaxe, les parenth`ses sont optionnelles autour de la condition, mais je vous conseille de e les mettre syst´matiquement pour une meilleure lisibilit´. Le code suivant e e affiche la variable $s si elle est d´finie : e print "$s\n" if( defined($s) ); On notera que cette syntaxe ne permet pas l’usage d’un else. L’instruction unless a exactement le mˆme rˆle que le if, a la diff´rence e o ` e que les instructions seront effectu´es si la condition est fausse (il est aussi e moins d´paysant d’en faire des forˆts). unless( expression ) est ´quivalent e e e a if( !(expression) ) dans toutes les constructions pr´c´demment cit´es. ` e e e

3.2

Les boucles

Les boucles permettent d’ex´cuter plusieurs fois les mˆmes instructions e e sans avoir a ´crire plusieurs fois les mˆmes lignes de code. Bien souvent ` e e 27

Introduction a la programmation en Perl `

c sylvain@lhullier.org

nous avons besoin de modifier une variable a chaque ´tape ; dans ce cas ` e nous utiliserons l’instruction for (pour en fran¸ais) dont voici la syntaxe : c for( initialisation; condition; incr´ment ) e { instructions; } La boucle for prend trois expressions entre parenth`ses : la premi`re e e expression permet d’initialiser la variable de boucle, la deuxi`me est une e condition de continuation et la derni`re permet de modifier la valeur de la e variable de boucle. Quand la boucle d´marre, la variable est initialis´e (expression 1) et e e le test est effectu´ (expression 2). Si cette condition est v´rifi´e, le bloc e e e d’instructions est ex´cut´. Quand le bloc se termine, la variable est modifi´e e e e (expression 3) et le test est de nouveau effectu´ (expression 2). Si la condition e est v´rifi´e, le bloc d’instructions est r´-ex´cut´ avec la nouvelle valeur pour e e e e e la variable de boucle. Tant que le test reste vrai, le bloc d’instructions et l’expression de modification de la variable sont ex´cut´s. A l’arrˆt de la boucle, les instructions e e ` e qui suivent la boucle sont ex´cut´es. e e L’exemple suivant affiche tous les entiers pairs de 0 a 20 inclus : ` for( my $i=0; $i<=20; $i+=2 ) { print "$i\n"; } La boucle s’arrˆte lorsque $i vaut 22. Cette variable est d´clar´e dans e e e le bloc d’initialisation et n’existe donc que dans la boucle. Notez qu’il est tout a fait possible d’utiliser une variable pr´-existante comme variable de ` e boucle (et donc de ne pas faire de my dans la partie initialisation) ; dans ce cas, apr`s ex´cution de la boucle, la variable vaut la derni`re valeur qui lui e e e a ´t´ affect´e au cours de la boucle. ee e Une autre boucle existe : la boucle while (tant que en fran¸ais) dont voici c la syntaxe : while( condition ) { instructions; } 28

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Les instructions sont effectu´es tant que la condition est vraie. La partie e initialisation doit avoir ´t´ effectu´e avant la boucle ; la partie modification ee e de la variable doit avoir lieu dans le bloc d’instructions. L’exemple suivant affiche lui aussi les entiers pairs de 0 a 20 : ` my $i = 0; while( $i <= 20 ) { print "$i\n"; $i+=2; } La seule diff´rence entre les deux exemples est le fait que, dans le cas du e while, la variable $i existe apr`s la boucle. e Comme pour le if, certaines facilit´s sont offertes pour le while. Tout e d’abord, la syntaxe suivante est correcte : instruction while( condition ); Elle permet d’ex´cuter plusieurs fois une instruction et une seule tant e qu’une condition est v´rifi´e. e e Ensuite, il existe une instruction until (jusqu’` en fran¸ais) qui a la a c mˆme syntaxe que le while mais qui demande une condition d’arrˆt (comme e e unless pour if) : until(condition) est ´quivalent a while(!(condition)) e ` Lors de l’ex´cution d’une boucle, il est fr´quent de rencontrer des cas e e particuliers que l’on souhaiterait sauter ou pour lesquels on aimerait mettre fin a la boucle. Les instructions next, last et redo vont nous servir a cela ` ` dans les boucles for, while ou until. L’instructions next (suivant en fran¸ais) provoque la fin de l’ex´cution c e du bloc, le programme ´value directement l’incr´ment (dans le cas d’une e e boucle for) puis le test est effectu´. e L’instructions last (dernier en fran¸ais) provoque la fin de la boucle, ni c l’incr´ment ni le test ne sont effectu´s. e e L’instructions redo (refaire en fran¸ais) provoque le red´marrage du bloc c e d’instructions sans que la condition ni l’incr´mentation ne soient effectu´es. e e L’exemple suivant est une autre fa¸on d’imprimer a l’´cran les entiers c ` e pairs de 0 a 20 : ` my $i = -1; while( 1 ) {

# 1 est vrai

29

Introduction a la programmation en Perl ` $i++; last if( $i > 20 ); next if( $i%2 != 0 ); print "$i\n"; }

c sylvain@lhullier.org

Dans le cas o` l’on souhaite ex´cuter le bloc d’instruction une fois avant u e d’effectuer le test, on peut utiliser la syntaxe suivante : do { instruction; } while( condition ); Pour des raisons trop longues a exposer ici, il ne faut pas utiliser les ` instructions next, last et redo dans le cas de la boucle do while. Nous verrons dans la suite qu’il existe une autre structure de boucle : foreach. Elle permet d’it´rer sur les ´l´ments d’une liste (notion que nous e ee aborderons a cette occasion). Vous verrez alors qu’en Perl on utilise beau` coup le foreach et assez peu le for(;;).

3.3

Un exemple

Voici un petit exemple de programme Perl ; il n’est pas tr`s utile dans la e vie de tous les jours, mais il utilise beaucoup des notions abord´es jusqu’ici. e Si vous parvenez a comprendre tout ce qu’il fait, vous n’aurez pas perdu ` votre temps a le lire ! ` 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: #!/usr/bin/perl -w use strict; my $v ="##########"; for( my $i=9; $i>0; $i-- ) { print("$i impair\n") if( $i % 2 ); print( "-"x$i . "\n") unless( $i % 3 ); substr( $v, $i, 0 ) = $i; } print("$v\n"); 30

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Voici le d´tail du rˆle des lignes : e o • 1: Le shebang Perl avec l’option -w (affichage de messages d’avertissement) • 2: Cette instruction rend le langage moins permissif, je vous conseille de toujours la placer au d´but de vos programmes. e • 3: Nous d´clarons et initialisons une variable scalaire. e • 4: Une boucle for. D´claration et initialisation a 9 de la variable de e ` boucle $i. Nous continuerons tant qu’elle est strictement positive ; a ` chaque ´tape nous la d´cr´menterons : elle variera donc de 9 a 1. e e e ` • 5 et 11: accolades d´limitant le bloc de la boucle. e • 6 et 7: affichage d’une chaˆ dans le cas o` $i est impair. ıne u • 8 et 9: affichage d’une chaˆ dans le cas o` $i est multiple de 3. Cette ıne u chaˆ comporte $i caract`res moins (-). ıne e • 10: insertion de $i dans la chaˆ $v en position $i (une longueur de ıne 0 provoque une insertion et non un remplacement). • 12: Affichage de la variable $v L’affichage suivant est donc effectu´ : e 9 impair --------7 impair -----5 impair 3 impair --1 impair #1#2#3#4#5#6#7#8#9# Avez-vous tous compris?

31

Introduction a la programmation en Perl `

c sylvain@lhullier.org

32

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 4

Listes et tableaux
Les scalaires et les expressions de base n’ont maintenant plus aucun secret pour vous. Des notions plus complexes et des fonctions plus puissantes sont alors a notre port´e. C’est le cas des listes, des tableaux et de l’impres` e sionnant arsenal de fonctions Perl permettant de les manipuler ; vous verrez tout ce qu’il est possible de faire en Perl avec ces deux concepts a priori anodins. Une liste est une suite (donc ordonn´e) de valeurs scalaires. Nous verrons e comment cr´er une liste, la manipuler, la parcourir etc. e Une variable de type tableau peut contenir plusieurs valeurs scalaires. Cette notion est pr´sente dans de nombreux langages de programmation et e ne posera sans doute probl`me a personne. e ` Les passerelles entre listes et tableaux sont nombreuses et tr`s intuitives e en Perl. C’est pour cela que nous n’entrerons pas ici dans les d´tails de la dise tinction entre liste et tableau. Dans ce document, j’utiliserai chacun des deux termes a bon escient sans forcement indiquer explicitement pourquoi j’utilise ` l’un plutˆt que l’autre, mais les notions pourront apparaˆ o ıtre naturelles au lecteur sans qu’il ne soit n´cessaire de pr´ciser les choses formellement. e e

4.1

Valeurs de listes

En Perl, une liste peut ˆtre repr´sent´e par les valeurs qu’elle doit contee e e nir encadr´es par un couple de parenth`ses. Par exemple (2,5,-3) est une e e liste de 3 scalaires : 2, 5 et -3. Autre exemple (2,’age’,"Bonjour $prenom") est aussi une liste ; en effet les listes contenant des scalaires, rien ne nous empˆche d’en constituer une comportant des nombres et des chaˆ e ınes de caract`res mˆl´s. La liste vide se repr´sente sous la forme suivante : () e ee e 33

Introduction a la programmation en Perl `

c sylvain@lhullier.org

L’op´rateur d’intervalle .. permet de cr´er une liste comportant des e e valeurs successives entre deux bornes. La liste (1..10) comporte tous les entiers de 1 a 10 ; on aurait pu aussi ´crire (1,2,3,4,5,6,7,8,9,10), mais ` e cette derni`re notation est bien plus lourde. Il faut savoir que les valeurs e des bornes ne doivent pas obligatoirement ˆtre des nombres : par exemple, e la liste (’a’..’z’) comporte toutes les lettres de l’alphabet, en minuscule et dans l’ordre. Il est aussi possible de sp´cifier les bornes a l’aide de vae ` riables : ($debut..$fin) On comprendra qu’il n’est pas toujours possible de r´soudre ce type de liste (par exemple si $debut vaut 1 et $fin vaut e ’a’), dans ce cas la liste est vide. Dernier exemple, la liste (1..10, "age", "a".."z") comporte 37 ´l´ments (10+1+26). ee La liste (1,2,("nom",12),"aaa",-1) n’est pas une liste a 5 ´l´ments ` ee dont le troisi`me serait une autre liste, c’est en fait une liste a 6 ´l´ments. e ` ee On aurait pu ´crire (1,2,"nom",12,"aaa",-1) et on aurait obtenu la mˆme e e liste. On appelle cela l’aplatissement (ou la lin´arisation) des listes. Pour e constituer une liste de listes, il faudra faire usage de r´f´rences (notion que ee nous aborderons plus tard). L’op´rateur de r´p´tition (x), que l’on a d´j` appliqu´ aux chaˆ e e e ea e ınes de caract`res pr´c´demment, s’applique aussi aux listes : (2,10) x 3 est une e e e liste a 6 ´l´ments valant (2,10,2,10,2,10). ` ee

4.2

Manipulation de tableaux

Pour simplifier les choses, un tableau est une variable qui peut avoir une liste pour valeur. Une telle variable se d´clare de la sorte : my @t; On a alors e un tableau vide, c’est-`-dire sans ´l´ment. De mani`re plus explicite, voici a ee e comment d´clarer un tableau vide : e my @t = (); Pour lui donner une valeur lors de sa d´claration, il faut faire ainsi : e my @t = (3,’chaine’,"bonjour $prenom"); On a alors d´clar´ ce tableau en l’initialisant au moyen d’une liste. e e On peut acc´der directement a un ´l´ment d’un tableau grˆce a son e ` ee a ` indice : $t[indice] repr´sente l’´l´ment d’indice indice du tableau @t. Notez e ee bien que la globalit´ du tableau se repr´sente au moyen d’une arobase @t e e alors qu’un ´l´ment particulier est d´sign´ a l’aide d’un dollar $t[indice], ee e e ` cette derni`re expression ´tant bien une variable de type scalaire (le dollar e e est r´serv´ aux scalaires en Perl). e e 34

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Les indices des tableaux en Perl commencent a 0 (comme en C), ce qui ` signifie que le premier ´l´ment du tableau @t est $t[0] et le deuxi`me $t[1] ee e etc. Voici un petit exemple d’utilisation de tableau : my @t = (3,5); # d´claration et initialisation e $t[1] = 4; # affectation d’un el´ment ´ e print "$t[0]\n"; # affichage d’un el´ment ´ e Il est int´ressant de savoir qu’il est possible d’acc´der au dernier ´l´ment e e ee d’un tableau en utilisant l’indice -1 : $t[-1] est le dernier ´l´ment de @t. De ee la mˆme fa¸on, $t[-2] est l’avant-dernier, etc. e c Il est possible de connaˆ ıtre l’indice du dernier ´l´ment d’un tableau ee @t grˆce a la variable $#t On a donc $t[$#t] ´quivalent a $t[-1] (ce a ` e ` dernier ´tant bien plus lisible). Il peut ˆtre utile de savoir que l’exprese e sion scalar(@t) (c’est-`-dire l’utilisation d’un tableau en contexte scalaire) a donne le nombre d’´l´ments du tableau @t (ce qui vaut 1 de plus que $#t) ; ee $x=@t donnerait la mˆme chose. e Il faut savoir que vous ne g´n´rerez pas d’erreur (d´bordement ou autre) e e e si vous tentez d’acc´der a un ´l´ment au-del` du dernier. La valeur de cet e ` ee a ´l´ment sera simplement undef et le programme continuera. Depuis la veree sion 5.6 de Perl, l’instruction exists (que l’on retrouvera pour les tables de hachage) permet de tester l’existence d’un ´l´ment d’un tableau : ee if( exists( $t[100] ) ) { ... } Ce test sera vrai si l’´l´ment d’indice 100 du tableau @t existe. Ce qui ee est diff´rent du test suivant : e if( defined( $t[100] ) ) { ... } Car on teste ici si l’expression $t[100] vaut undef ou non, ce qui peut ˆtre vrai dans deux cas : soit l’´l´ment existe et vaut undef, soit l’´l´ment e ee ee n’existe pas ... Voici une autre illustration du fait que vous n’avez pas a vous soucier de ` probl`mes d’allocation m´moire : e e my @t = (3,23.4,"as"); $t[1000] = 8; 35

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Ce programme est correct et fonctionne parfaitement : l’affectation a l’in` dice 1000 agrandit le tableau d’autant ... Les ´l´ments d’indice compris entre ee 3 et 999 valent undef et scalar(@t) vaut 1001. C’est si facile finalement ! Un tableau qu’il est utile de connaˆ est @ARGV. Cette variable sp´ciale ıtre e est toujours d´finie (mˆme dans les fonctions) et ne n´cessite pas de d´clae e e e ration. Elle contient les arguments de la ligne de commande du programme. Les trois fa¸ons de lancer un programme en Perl sont susceptibles d’utiliser c @ARGV: perl -w -e ’... code perl ...’ arg1 arg2 arg3 perl -w script.pl arg1 arg2 arg3 ./script.pl arg1 arg2 arg3 Ces trois programmes sont lanc´s avec les trois mˆmes arguments. Sachez e e que, contrairement au langage C, le nom du programme n’est pas contenu dans @ARGV qui ne comporte donc que les arguments au sens strict. La variable sp´ciale $0 (comme en shell) contient le nom du programme (nul e besoin de d´clarer cette variable pour l’utiliser). e

4.3

Affectations

Il est possible d’affecter un tableau a un autre tableau en une seule ` instruction : @t = @s; Cette instruction copie le tableau @s dans le tableau @t. Le tableau @t perd ses anciennes valeurs, prend celle de @s et sa taille devient celle de @s : on obtient bien deux tableaux tout a fait identiques (et distincts, la ` modification de l’un n’entraˆ ınant nullement la modification de l’autre). Voici d’autres instructions d’affectation mˆlant tableaux et listes : e • ($a,$b) = (1,2); Cette instruction affecte une valeur a chacune des ` variables de la liste de gauche : $a re¸oit 1 et $b re¸oit 2. c c • ($a,$b) = (1,2,3); Les mˆmes affectations sont effectu´es ici, la vae e leur 3 n’´tant d’aucune utilit´. e e • ($a,$b) = (1); L’affectation a $a de la valeur 1 est effectu´e et $b ` e est mis a undef (son ancienne valeur est perdue). ` • ($a,$b) = @t; Les variables cit´es a gauche re¸oivent les premi`res e ` c e valeurs du tableau @t : $a en re¸oit le premier ´l´ment ou undef si @t c ee est vide ; $b re¸oit le deuxi`me ´l´ment ou undef si @t il ne contient c e ee qu’un ´l´ment. ee 36

c sylvain@lhullier.org

Introduction a la programmation en Perl `

• @t = (1,2); Cette instruction r´initialise le tableau @t (dont les ane ciennes valeurs sont toutes perdues, y compris celles d’indice diff´rent e de 0 et 1) en lui affectant les valeurs de droite : on obtient donc un tableau a deux ´l´ments. ` ee • ($a,$b) = Fonction(); Nous verrons un peu plus loin comment ´crire e une fonction, et comment lui faire renvoyer une liste : ici l’affectation se fait dans les mˆmes conditions que pour les trois premiers cas. e • ($a,$b) = ($b,$a); Cette instruction est la plus savoureuse : on peut ´changer deux variables Perl sans avoir a en utiliser une troisi`me ... e ` e (Ai-je d´j` dit que Perl s’occupe lui-mˆme de la m´moire?) ea e e

4.4

Multi-d´claration e

Pour d´clarer plusieurs variables avec un seul my, le d´butant aurait e e tendance a ´crire la chose suivante (il n’y a pas de honte !) : `e my $a,$b; # Incorrect !

Ceci est incorrect. Pour pouvoir faire cela, il nous faut utiliser une liste : my ($a,$b); Les variables $a et $b sont cr´´es et valent undef. Pour leur affecter des ee valeurs, il faut l` aussi utiliser une liste (ou un tableau) : a my ($a,$b) = (1,2); my ($c,$d) = @t; Les mˆmes r`gles que pour l’affectation de listes s’appliquent ici. e e

4.5

Retour sur l’aplatissement des listes

On retrouve la notion d’aplatissement des listes avec les tableaux : @t = (1,2,"age"); @t2 = (10,@t,20); Le tableau @t2 ne comporte pas trois ´l´ments dont celui du milieu serait ee lui-mˆme un tableau, mais contient les cinq ´l´ments, r´sultat de l’aplatissee ee e ment du tableau @t dans la liste de droite lors de l’affectation de @t2. Cette affectation a eu le mˆme r´sultat qu’aurait eu la suivante : e e @t2 = (10,1,2,"age",20); 37

Introduction a la programmation en Perl `

c sylvain@lhullier.org

4.6

Absorption d’une liste par un tableau

La syntaxe suivante est int´ressante a connaˆ : e ` ıtre ($a,@t) = @s; Le membre gauche de l’affectation est constitu´ d’une liste comportant e une variable scalaire et un tableau. Il n’y a pas a proprement parler d’apla` tissement de liste car il s’agit ici d’une l-value (membre gauche d’une affectation), mais la variable $a re¸oit le premier ´l´ment du tableau @s et le c ee tableau @t absorbe tous les autres (@s n’´tant bien-sˆ r pas modifi´). e u e En fait dans cette syntaxe, le premier tableau rencontr´ dans la liste de e gauche re¸oit tous les ´l´ments restant de la liste de droite. D’´ventuelles c ee e autres variables qui le suivraient (cas idiot, mais bon...) serait mises a undef ` s’il s’agit de scalaires et a vide s’il s’agit de tableaux. Par exemple, l’affec` tation suivante : @s = (10,1,2,"age",20); ($a, @t, @u, $b) = @s; ´quivaut a : e ` @s $a @t @u $b = = = = = (10,1,2,"age",20); 10; (1,2,"age",20); (); undef;

Simple et intuitif.

4.7

La structure de boucle foreach

Cette instruction permet de parcourir une liste. Son impl´mentation ope timis´e dans l’interpr´teur Perl rend son usage bien plus efficace qu’un pare e cours qui utiliserait une variable indicielle incr´ment´e a chaque tour d’une e e ` boucle for. Sa syntaxe est la suivante : foreach variable ( liste ) { instructions } ` A chaque tour de boucle, la variable aura pour valeur un ´l´ment de la ee liste, la liste ´tant parcourue dans l’ordre. Aucune modification ni supprese sion dans la liste n’est effectu´e par d´faut dans ce type de boucle. Il vous est e e possible de modifier la variable de boucle (ce qui aura pour effet de modifier l’´l´ment en question), mais, par d´faut, le parcours n’est pas destructif. ee e 38

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Par exemple : foreach $v (1,43,"toto") { print "$v\n"; } Ce petit programme affiche chaque ´l´ment de la liste sur une ligne. Ces ee autres exemples sont valides eux-aussi : foreach $v (@t) { .... } foreach $v (32,@t,"age",@t2) { .... } Dans le premier cas, les ´l´ments du tableau @t sont parcourus. Le second ee exemple illustre les ph´nom`nes d’aplatissement des listes qui se retrouvent e e ici aussi. Il est possible de d´clarer la variable de boucle dans le foreach de la e mani`re suivante : e foreach my $v (@t) { print "$v\n"; } Il est aussi possible de ne pas utiliser explicitement de variable de boucle ; dans ce cas c’est la variable sp´ciale $_ qui sera automatiquement utilis´e : e e foreach (@t) { print "$_\n"; } Comme pour les autres boucles, l’instruction next passe a la valeur sui` vante sans ex´cuter les instructions qui la suivent dans le bloc. L’instruction e last met fin a la boucle. ` Voici un petit exemple d’utilisation de foreach affichant des tables de multiplication : #!/usr/bin/perl -w use strict; die("Usage: $0 <n> <n>\n") if( !defined( $ARGV[1] ) ); foreach my $i (1..$ARGV[0]) 39

Introduction a la programmation en Perl ` { foreach my $j (1..$ARGV[1]) { printf( "%4d", $i*$j ); } print "\n"; } Et le voici a l’œuvre : ` ./mult.pl Usage: ./mult.pl <n> <n> ./mult.pl 5 3 1 2 3 2 4 6 3 6 9 4 8 12 5 10 15 Passons a la suite. `

c sylvain@lhullier.org

4.8

Fonctions de manipulation de tableaux

Il existe de nombreuses fonctions permettant de manipuler les tableaux. Pour chacun des exemples qui vont suivre, je suppose que nous avons un tableau @t d´clar´ de la sorte : e e my @t = (1,2,3,4); • Ajout et suppression a gauche ` • La fonction unshift prend en arguments un tableau et une liste de valeurs scalaires ; ces valeurs sont ajout´es au d´but du tae e bleau : unshift(@t,5,6); @t vaut alors la liste (5,6,1,2,3,4). • La fonction shift prend un tableau en argument ; elle supprime son premier ´l´ment (les autres sont alors d´cal´s) et renvoie cet ee e e ´l´ment : ee $v = shift(@t); 40

c sylvain@lhullier.org

Introduction a la programmation en Perl `

$v vaut alors 1 et @t la liste (2,3,4). • Ajout et suppression a droite ` • La fonction push prend en argument un tableau et une liste de valeurs scalaires ; ces valeurs sont ajout´es a la fin du tableau : e ` push(@t,5,6); @t vaut alors la liste (1,2,3,4,5,6). • La fonction pop prend un tableau en argument ; elle supprime son dernier ´l´ment et renvoie cet ´l´ment : ee ee $v = pop(@t); $v vaut alors 4 et @t la liste (1,2,3). • Inversion En contexte de liste, la fonction reverse prend en argument une liste et renvoie la liste invers´e, c’est-`-dire celle dont les ´l´ments sont pris e a ee dans le sens oppos´ : e @s = reverse(@t); @s vaut alors la liste (4,3,2,1) et @t n’est pas modifi´e. e Avec de telles fonctions, il est alors envisageable de manipuler des objets algorithmiques tels que les piles et les files. Une pile est un lieu de stockage ayant pour particularit´ que le dernier ´l´ment a y ˆtre entr´ sera le premier e ee ` e e a en sortir (last in-first out) comme pour une pile d’assiettes sur une ´tag`re ` e e de placard. On peut utiliser pour cela un tableau, avec les fonctions push pour ajouter un ´l´ment et pop pour en prendre un. De fa¸on analogue, une ee c file est un endroit o` le premier entr´ est le premier a sortir (first in-first out) u e ` comme pour une file a une caisse de magasin. On peut par exemple utiliser ` les fonctions push pour ajouter un ´l´ment et shift pour en prendre un. ee D’autre manipulations plus complexes du contenu d’un tableau sont possibles avec la fonction splice, mais je vous renvoie a la documentation pour ` les d´tails. e 41

Introduction a la programmation en Perl `

c sylvain@lhullier.org

4.9

L’op´rateur qw e

L’op´rateur qw nous permet de cr´er facilement une liste de chaˆ e e ınes de caract`res. En effet, il peut sembler p´nible de constituer une longue liste e e de tels ´l´ments en raison du fait qu’il faut d´limiter chacun d’entre eux au ee e moyen de simples ou de doubles quotes : @t = ( ’Ceci’, ’est’, ’quelque’, ’peu’, ’p´nible’, e ’`’, ’´crire’, ’,’, ’non’, ’?’ ); a e Avec qw, ceci devient tout a coup plus lisible : ` @t = qw(Cela est bien plus facile a faire non ?); ` La chaˆ de caract`re sera d´coup´e selon les espaces, les tabulations et ıne e e e les retours a la ligne. ` Les d´limiteurs les plus souvent utilis´s sont les parenth`ses (comme dans e e e l’exemple pr´c´dent) ainsi que les slashs : e e @t = qw/Ou alors comme cela .../; Cette fonction est bien pratique mais peut ˆtre source d’erreurs, voyez e l’exemple suivant : @t = qw/ attention ’aux erreurs’ b^tes /; e Les simples quotes (’) semblent indiquer que le programmeur souhaite constituer un seul ´l´ment comportant les mots aux et erreurs ; ce n’est ee pas ce qui est fait ici. En effet, ni les simples quotes ni les doubles quotes ne constituent un moyen de regrouper des mots pour l’op´rateur qw. La liste e ainsi cr´´e comporte donc 4 ´l´ments ; on aurait pu ´crire : ee ee e ("attention","’aux","erreurs’","b^tes"). e

42

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 5

´ Ecrire une fonction
Une fonction est un ensemble d’instructions regroup´es de mani`re a ˆtre e e `e utilis´es plusieurs fois sans avoir a dupliquer du code. e `

5.1

D´claration e

Le mot-clef sub permet de d´finir des fonctions en Perl. Les arguments e d’une fonction sont des valeurs scalaires, a l’exclusion de toutes autres (on ` verra comment faire en sorte de passer un tableau en argument) ; ces param`tres sont accessibles via la variable sp´ciale @_ (qui est donc un tableau). e e Modifier une valeur de @_ modifiera les variables d’appel, il est donc d’usage d’en faire une copie avant manipulation. sub maJolieFonction { my ($x,$y,$t) = @_; ... instructions ... return $z; } Ces quelques lignes d´finissent une nouvelle fonction dont le nom est e maJolieFonction. Cette fonction copie dans trois variables locales les trois premi`res valeurs du tableau @_, c’est-`-dire ses trois premiers param`tres e a e (les r`gles classiques d’affectation entre listes et tableaux s’appliquent ici). e Je vous conseille de toujours commencer vos fonctions par une ligne copiant les valeurs de @_ et de ne plus utiliser @_ dans la suite de la fonction (sauf cas sp´cial). Si votre fonction attend un seul param`tre, la syntaxe peut ˆtre e e e 43

Introduction a la programmation en Perl ` la suivante : my ($x) = @_; mais ne peut pas ˆtre : e my $x = @_; #incorrect

c sylvain@lhullier.org

Cette ligne est incorrect car, dans ce cas, la variable $x aurait pour valeur le nombre de param`tres (affectation d’un tableau a un scalaire). La syntaxe e ` suivante peut aussi ˆtre utile : e my ($x,@t) = @_; la variable $x re¸oit le premier param`tre et le tableau @t re¸oit tous les c e c param`tres restants. e Enfin, une autre ´criture que vous verrez souvent dans les programmes e Perl est la suivante : my $x = shift; celle-ci s’appuie sur le fait que dans une sous-routine, la fonction shift travaille par d´faut sur @_. e L’instruction return met fin a l’ex´cution de la fonction et on peut lui ` e fournir une expression qui sera alors la valeur de retour de la fonction.

5.2

Appel

La fonction ainsi d´finie peut ˆtre appel´e au moyen de la syntaxe suie e e vante : maJolieFonction(10,20,30); Dans ce cas, l’´ventuelle valeur de retour est ignor´e. Pour r´cup´rer e e e e cette valeur : $v = maJolieFonction(10,20,30); Il est possible d’omettre les parenth`ses lors de l’appel a une fonction : e ` maJolieFonction 10,20,30; # ` eviter A ´ 44

c sylvain@lhullier.org

Introduction a la programmation en Perl `

mais cela peut cr´er des ambigu¨ es et je vous d´conseille donc cette e ıt´ e syntaxe. S’il est possible en Perl d’imposer le nombre d’arguments pour une fonction (nous n’en parlerons pas ici), cela n’est pas fait par d´faut. Rien ne e nous empˆche en effet d’appeler la fonction maJolieFonction pr´c´demment e e e d´finie avec deux ou quatre arguments, alors qu’elle semble en attendre e trois ; si on l’appelle avec deux arguments, la variable $t vaudra undef ; par contre si on l’appelle avec plus de trois arguments, les valeurs suivantes seront ignor´es. Mais cette particularit´ du langage est parfois bien pratique, e e notamment pour ´crire des fonctions a nombre variable d’arguments. e `

5.3

Visibilit´ des variables e

Les variables d´clar´es au moyen de my dans une fonction ne seront e e visibles qu’` l’int´rieur mˆme de la fonction, dans le code qui suit la d´claa e e e ration. Dans une fonction, il est possible d’acc´der aux variables d´finies a e e ` la ’racine’ du programme (c’est-`-dire en dehors de toute fonction) : il s’agit a donc de variables globales. Si une variable locale a le mˆme nom qu’une e variable globale, cette derni`re est masqu´e par la variable locale : e e my $a = 3; my $b = 8; my $c = 12; sub maJolieFonction { my $a = 5; print "$a\n"; print "$b\n"; $c = 15; print "$c\n"; } maJolieFonction(); print "$a\n"; print "$b\n"; print "$c\n";

# # # #

affiche 5 affiche 8 modification de la variable globale affiche 15

# affiche 3 # affiche 8 # affiche 15

De mani`re plus g´n´rale, les variables d´clar´es au moyen de my sont e e e e e visibles jusqu’` la fin du plus petit bloc qui les englobe. En particulier, dans a une fonction... sub maJolieFonction2 45

Introduction a la programmation en Perl ` { my $d = -3; if( ... ) { my $d = 4; my $e = 8; print "$d\n"; print "$e\n"; } print "$d\n"; print "$e\n"; }

c sylvain@lhullier.org

# affiche 4 # affiche 8 # affiche -3 # $e n’existe pas ici

5.4

Une liste pour valeur de retour

Il est tout a fait possible de faire renvoyer plusieurs scalaires a une fonc` ` tion, il suffit juste d’utiliser une liste. Voici des exemples de syntaxe de liste renvoy´e par des fonctions : e return ($x,$z); return @t; Dans le second cas, le tableau est converti en liste. Et voici comment il est possible de r´cup´rer ces valeurs : e e @s = fonction(...); ($j,$k) = fonction(...); Ces deux mani`res de proc´der peuvent parfaitement ˆtre utilis´es chae e e e cune dans les deux cas de return pr´-cit´s (ce sont toujours les mˆmes r`gles e e e e d’affectation qui s’appliquent).

5.5
1: 2: 3: 4: 5:

Premier exemple de fonction
#!/usr/bin/perl -w use strict; my $t = "Bonjour Larry"; print "$t\n"; sub f

Voici un exemple complet de programme en Perl avec une fonction :

# variable globale # avec ou sans parenth`ses e

46

c sylvain@lhullier.org

Introduction a la programmation en Perl `

6: 7: 8: 9: 10: 11: 12: 13:

{ my ($x,$z) = @_; my $m = $x*$z; printf("%d\n", $m); return ($x+$z,$m); } my @t = f(3,5); print "$t $t[0] $t[1]\n"; # deux arguments attendus

# retourne une liste

Un bon programme Perl commence toujours par les premi`re et deuxi`me e e lignes. Si la variable scalaire $t, elle, est globale, en revanche les variables $x, $z et $m sont locales a la fonction. En ligne 12, le tableau @t re¸oit ` c pour valeur la liste renvoy´e par la fonction. Notez bien qu’il n’y a aucun e conflit entre les variables $t et @t ; en effet, l’instruction de la derni`re ligne e proc`de d’abord a l’affichage de la variable scalaire $t puis du premier et e ` deuxi`me ´l´ments du tableau @t (les crochets permettent de savoir qu’il e ee s’agit d’´l´ments d’un tableau). ee

5.6

Autre exemple : une fonction r´cursive e

Voici un exemple de fonction. Elle est r´cursive (c’est-`-dire qu’elle fait e a appel a elle-mˆme) : nous allons calculer la factorielle d’un nombre. Par ` e d´finition, F(0)=F(1)=1 et F(n)=n×F(n-1) pour tout n sup´rieur a 1 : e e ` sub Fact { my ($n) = @_; return 1 if( $n == 1 || $n == 0 ); return $n * Fact($n-1); } print Fact(5)."\n"; # affiche 120 Aussi lisible que dans tout autre langage.

47

Introduction a la programmation en Perl `

c sylvain@lhullier.org

48

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 6

Autres fonctions sur les listes
Vous savez maintenant manipuler des tableaux et des listes, vous savez aussi ´crire des fonctions : vous voila arm´s pour aborder les tr`s puissantes e e e et bien pratiques fonctions de gestion qui suivent.

6.1

Joindre les ´l´ments dans une chaˆ avec join ee ıne

La fonction join prend en param`tre un scalaire et une liste ; elle renvoie e une chaˆ de caract`res comportant les ´l´ments de la liste, concat´n´s et ıne e ee e e s´par´s par ce premier param`tre scalaire. Les arguments pass´s ne sont pas e e e e modifi´s. e scalaire = join( s´parateur, liste ); e Voici quelques exemples : • $s = join(" ",1,2,3); La variable $s vaut alors la chaˆ "1 2 3". ıne • $s = join(’,’,$x,$y,$y); Les valeurs des trois variables sont jointes en les alternant avec des virgules. Le r´sultat est affect´ a $s. e e` • $s = join(" : ",@t); La variable vaut alors la concat´nation des e valeurs du tableau @t avec " : " pour s´parateur. e

6.2

D´couper une chaˆ de caract`res en liste avec e ıne e split

La fonction split prend en param`tre un s´parateur et une chaˆ de cae e ıne ract`res ; elle renvoie la liste des ´l´ments de la chaˆ de caract`res d´limit´s e ee ıne e e e par le s´parateur. Le s´parateur est une expression r´guli`re, notion que nous e e e e aborderons dans la suite, mais dont le minimum de connaissances suffit a ` 49

Introduction a la programmation en Perl `

c sylvain@lhullier.org

cette fonction ; admettez ici qu’une telle expression est a placer entre slashs ` (/). Les arguments pass´s ne sont pas modifi´s. e e liste = split( /s´parateur/, chaˆne ); e ı Voici quelques exemples : • @t = split(/-/,"4-12-455"); Le tableau comporte alors les ´l´ments ee 4, 12 et 455. • ($x,$y) = split(/==/,$v); Les deux variables auront pour valeur les deux premi`res chaˆ e ınes de caract`res qui soient s´par´es par deux e e e signes d’´galit´. e e • print join(’:’,split(/ /,’salut ici’)); Affiche salut:ici (il existe des m´thodes plus efficaces et plus lisibles de faire cela...). e

6.3

Trier une liste avec sort

La fonction sort prend en param`tre un bloc d’instructions optionnel et e une liste ; elle renvoie une liste tri´e conform´ment au crit`re de tri constitu´ e e e e par le bloc d’instructions. La liste pass´e en argument n’est pas modifi´e. e e liste2 = sort( liste1 ); liste2 = sort( { comparaison } liste1 ); (attention a ne pas mettre ` de virgule entre le bloc d’instructions et la liste) Tout au long du tri, le bloc d’instruction sera ´valu´ pour comparer deux e e valeurs de la liste ; ces deux valeurs sont localement affect´es aux variables e sp´ciales $a et $b qui ne sont d´finies que dans le bloc et sur lesquels il e e faut donc effectuer la comparaison. Il faut faire particuli`rement attention e au fait que s’il existe des variables $a et $b dans le programme elles seront localement masqu´es par ces variables sp´ciales (source courante d’erreurs). e e Le bloc doit ˆtre compos´ d’une expression dont la valeur est : e e • positive, si $a doit ˆtre avant $b dans la liste r´sultat. e e • n´gative, si $b doit ˆtre avant $a. e e • nulle, s’ils sont ´quivalents. e C’est l` qu’entrent en jeu les op´rateurs de comparaison cmp et <=> : a e ils permettent de comparer respectivement les chaˆ ınes de caract`res selon e l’ordre lexical et les nombres selon l’ordre num´rique. Si la fonction sort est e appel´e sans bloc d’instruction, la liste est tri´e selon l’ordre lexical. e e Voici quelques exemples : • @s = sort( {$a cmp $b} @t ); La liste @s a pour valeur la liste @t tri´e selon l’ordre lexical. e 50

c sylvain@lhullier.org

Introduction a la programmation en Perl `

• @s = sort( @t ); Le fonctionnement est identique a l’exemple pr´` e c´dent. e • @s = sort( {$a <=> $b} @t ); Le crit`re de tri est ici num´rique. e e • @s = sort( {$a <=> $b or $a cmp $b} @t ); Une expression compos´e peut bien sˆ r servir de crit`re : le tri est ici d’abord num´rique e u e e puis lexical. Cela permet de placer ’8 navets’ avant ’12 carottes’, et ’12 carottes’ avant ’12 navets’. • @s = sort( { fonction($a,$b) } @t ); Vous pouvez ´crire votre e propre fonction de tri (` deux arguments) ; elle doit renvoyer un noma bre dont la valeur d´pend de l’ordre voulu (voir juste avant). e

6.4

S´lectionner des ´l´ments avec grep e ee

La fonction grep prend en param`tre un crit`re de s´lection et une liste ; e e e elle renvoie la liste des ´l´ments correspondant au crit`re. La liste pass´e en ee e e argument n’est pas modifi´e. e Le crit`re de s´lection peut ˆtre soit une expression r´guli`re (cas sur e e e e e lequel nous reviendrons plus tard), soit un bloc d’instructions (cas sur lequel nous allons nous ´tendre) : e liste2 = grep { s´lection } liste1; (attention : pas de parenth`ses ni de e e virgule) Les ´l´ments renvoy´s sont ceux pour lesquels l’´valuation du bloc d’insee e e tructions a pour valeur vrai. Durant cette ´valuation, chacune des valeurs e sera localement affect´e a la variable sp´ciale $_ sur laquelle les tests devront e ` e donc ˆtre effectu´s. e e Voici quelques exemples : • @t = grep { $_<0 } $x,$y,$z; Affecte a @t les ´l´ments n´gatifs de ` ee e la liste. • @s = grep { $_!=8 and $_!=4 } @t; Met dans @s les ´l´ments de ee @t diff´rents de 4 et de 8. e • @s = grep { fonction($_) } @t; Vous pouvez ´crire votre propre e fonction de s´lection ; elle doit renvoyer vrai ou faux selon si l’´l´ment e ee est a garder ou non. ` En contexte scalaire, la fonction grep renvoie le nombre d’´l´ments qui ee correspondent au crit`re : $n = grep { .... } @t; e La syntaxe de grep comportant une expression r´guli`re est la suivante : e e liste2 = grep( /regexp/, liste1 ); 51

Introduction a la programmation en Perl `

c sylvain@lhullier.org

En quelques mots, les ´l´ments renvoy´s seront ceux qui correspondront ee e a l’expression r´guli`re. Par exemple @s = grep( /^aa/, @t ); affecte a ` e e ` @s les ´l´ments de @t qui commencent par deux lettres a. Plus d’explications ee sur les expressions r´guli`res seront donn´es dans la suite. e e e J’ai affirm´ que la liste d’origine n’´tait pas modifi´e, mais il vous est e e e possible de le faire. Si, durant la s´lection, vous affectez une valeur a $_, la e ` liste sera modifi´e. Mais cela est sans doute une mauvaise id´e de modifier la e e liste pass´e en param`tre d’un grep car la fonction map est faite pour cela. e e

6.5

Appliquer un traitement ` tous les ´l´ments a ee avec map

La fonction map prend en param`tre un bloc d’instructions et une liste ; e elle applique le bloc a chacun des ´l´ments de la liste (modification possible ` ee de la liste) et renvoie la liste constitu´e des valeurs successives de l’expression e ´valu´e. e e liste2 = map( { expression } liste1 ); (attention a ne pas mettre de ` virgule entre le bloc d’instructions et la liste) La variable sp´ciale $_ vaut localement (dans le bloc d’instructions) e chaque ´l´ment de la liste. La valeur de la derni`re expression du bloc sera ee e plac´e dans la liste r´sultat. e e Voici quelques exemples : • @s = map( { -$_ } @t ); Le tableau @s aura pour valeurs les oppos´s des valeurs de @t. e • @p = map( { $_."s" } @t ); Tous les mots de @t sont mis au pluriel dans @p. • @s = map( { substr($_,0,2) } @t ); Le tableau @s aura pour valeurs les deux premiers caract`res des valeurs de @t. e • @s = map( { fonction($_) } @t ); Vous pouvez ´crire votre propre e fonction ; les valeurs qu’elle renverra seront plac´es dans @s. e Dans les exemples qui pr´c`dent, la liste d’origine n’est pas modifi´e e e e (sauf dans le dernier exemple o` elle peut l’ˆtre dans la fonction). Voici un u e exemple de modification de liste : map( { $_*=4 } @t ); Tous les ´l´ments de @t sont multipli´s par ee e quatre. 52

c sylvain@lhullier.org

Introduction a la programmation en Perl `

6.6

´ Un exemple : le crible d’Eratosth`ne e

Nous allons ici illustrer l’usage des listes et des tableaux par un exemple ´ math´matique : le crible d’Eratosth`ne. Cet algorithme permet de calculer e e tous les nombres premiers inf´rieurs a un nombre donn´ n. e ` e Son principe est le suivant : nous construisons tout d’abord la liste de tous les entiers de 2 a n. Ensuite, a chaque it´ration, nous supprimons de la ` ` e liste tous les multiples du premier nombre de la liste et signalons ce premier nombre comme ´tant premier. Au premier tour de boucle, je supprime tous e les nombres pairs et dis que 2 est premier. Au suivant, je supprime tous les multiples de 3 et affirme que 3 est premier. Au tour suivant, c’est le 5 qui est au d´but de la liste (4 ´tant multiple de 2, il a d´j` ´t´ supprim´), j’enl`ve e e eaee e e de la liste les multiples de 5 et annonce la primalit´ de 5 etc ... L’algorithme e se termine lorsque la liste est vide, j’ai alors d´termin´ tous les nombres e e premiers inf´rieurs a n. e ` Voici la fonction r´alisant cet algorithme en Perl : e sub Crible { my ($n) = @_; # Liste initiale : my @nombres = (2..$n); # Liste des nombres premiers trouv´s : e my @premiers = (); # Tant qu’il y a des el´ments (un tableau ´ e # en contexte bool´en vaut faux s’il est vide) : e while( @nombres ) { # On extrait le premier nombre my $prem = shift @nombres; # On indique qu’il est premier push @premiers, $prem; # On supprime ses multiples @nombres = grep { ( $_ % $prem )!=0 } @nombres; }

53

Introduction a la programmation en Perl ` # On renvoie la liste des nombres premiers return @premiers; }

c sylvain@lhullier.org

Quiconque a d´j` r´alis´ cet algorithme en C ou C++ comprendra la ea e e joie que cette concision procure ...

54

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 7

Tables de hachage
Les tables de hachage de Perl ne se retrouvent pas dans beaucoup d’autres langages ; pour les avoir souvent utilis´es en Perl, il est dur de repasser a des e ` langages qui n’en sont pas pourvus. Une table de hachage (hash table en anglais) est un type de donn´e en e Perl permettant d’associer une valeur a une clef. On peut dire d’un tableau ` (notion abord´e pr´c´demment) qu’il associe une valeur scalaire a un entier : e e e ` a la position i (pour i entier), une certaine valeur scalaire est pr´sente. ` e Une table de hachage va nous permettre d’aller au-del` : on pourra faire a correspondre une valeur scalaire (comme pour un tableau) a toute chaˆ de ` ıne caract`res (plutˆt qu’` un entier). e o a Je peux, par exemple, avoir envie de g´rer en Perl un index t´l´phonique e ee simple : chacun de mes amis a un num´ro de t´l´phone, je veux pouvoir e ee retrouver leur num´ro a partir de leur pr´nom. Je vais donc associer le e ` e num´ro au pr´nom : e e "Paul" -> "01.23.45.67.89" "Virginie" -> "06.06.06.06.06" "Pierre" -> "heu ..." Les pr´noms seront les clefs, c’est-`-dire le ”point d’entr´e” dans la table e a e de hachage (comme les indices num´raux le sont pour les tableaux). Les e num´ros de t´l´phone seront les valeurs associ´es a ces clefs. Il s’agit bien e ee e ` d’une association chaˆ de caract`res vers scalaire. ıne e Vous l’avez sans doute compris, dans une table de hachage, une clef n’est pr´sente qu’une seule fois et ne peut donc avoir qu’une seule valeur (comme e l’´l´ment d’un indice donn´ d’un tableau). Par contre, une valeur peut ˆtre ee e e associ´e a plusieurs clefs. e ` 55

Introduction a la programmation en Perl `

c sylvain@lhullier.org

7.1

D´claration et initialisation e

Une variable de type table de hachage se d´clare de la sorte : e my %h; On a alors une table de hachage vide (aucune clef). Il est possible de signaler explicitement que l’on d´clare une table de hachage vide : e my %h = (); Pour donner des valeurs initiales a notre table de hachage, on peut uti` liser la syntaxe suivante : my %h = ( "Paul" => "01.23.45.67.89", "Virginie" => "06.06.06.06.06", "Pierre" => "heu ..." ); Cette derni`re table de hachage est d´clar´e et initialis´e avec les clefs e e e e Paul, Virginie et Pierre ayant respectivement pour valeurs 01.23.45.67.89, 06.06.06.06.06 et heu ...

7.2

Acc´der ` un ´l´ment e a ee

Dans une table de hachage %h, on peut acc´der a la valeur d’une clef e ` au moyen de la syntaxe suivante : $h{clef} ; par exemple $h{Paul} vaut 01.23.45.67.89. Si la clef comporte d’autres caract`res que des lettres, e des chiffres et le soulign´ (underscore en anglais ’_’), il faut la d´limiter au e e moyen de simples ou de doubles quotes : $h{"Marie-Pierre"} ou $h{’Marie-Pierre’} En fait, cette syntaxe force un contexte de chaˆ de caract`res entre les ıne e accolades, ce qui fait qu’un mot simple (bareword en anglais) sera converti silencieusement en chaˆ de caract`res (mˆme en positionnant l’option -w). ıne e e De fa¸on similaire aux tableaux avec l’arobase (@t), la totalit´ d’une c e table de hachage se repr´sente au moyen du signe pourcentage (%h), alors e qu’une valeur particuli`re est d´sign´e a l’aide d’un dollar $h{clef}, cette e e e ` derni`re expression ´tant bien une variable de type scalaire. e e Voici quelques exemples de manipulation d’´l´ments de la table de haee chage %h : $h{Jacques} = "02.02.02.02.02"; print "T´l : $h{Jacques}\n"; e 56

c sylvain@lhullier.org

Introduction a la programmation en Perl `

$h{’Jean-Paul’} = "03.03.03.03.03"; if( $h{"Jean-Paul"} ne "Heu ..." ) { ... } La clef utilis´e pour cette syntaxe peut tout a fait ˆtre contenue dans e ` e une variable scalaire (qui sera ´valu´e en contexte de chaˆ de caract`res) : e e ıne e my $k = "Jacques"; $h{$k} = "02.02.02.02.02"; Elle peut mˆme ˆtre une expression plus complexe : e e sub f { return "Jac"; } $h{f().’ques’} = "02.02.02.02.02";

7.3

Parcours

Il existe trois fonctions permettant de parcourir une table de hachage. Dans les exemples fournis, nous consid´rerons que la table %h a ´t´ d´clar´e e ee e e ainsi : my %h = ( "Paul" => "01.23.45.67.89", "Virginie" => "06.06.06.06.06", "Pierre" => "heu ..." ); • keys : obtenir une liste des clefs Cette fonction prend en param`tre une table de hachage et renvoie e une liste comportant toutes les clefs de la table. L’ordre des clefs est quelconque, seule l’exhaustivit´ des clefs est garantie. e my @t = keys(%h); Le tableau @t peut par exemple valoir la liste ("Virginie", "Pierre", "Paul"). Cette fonction va nous permettre de parcourir toute la table de hachage en effectuant une boucle sur la liste des clefs : foreach my $k (keys(%h)) { print "Clef=$k Valeur=$h{$k}\n"; } 57

Introduction a la programmation en Perl `

c sylvain@lhullier.org

La variable de boucle $k prendra pour valeurs successives l’ensemble des clefs de la table, l’expression $h{$k} est la valeur associ´e a la clef e ` $k. Ce petit programme affichera donc tous les couples clef/valeur de la table %h. • values : obtenir une liste des valeurs De la mˆme fa¸on que keys renvoie une liste des clefs d’une table de e c hachage, la fonction values fournit une liste des valeurs ; pour cette fonction non plus l’ordre n’est pas garanti et seule l’exhaustivit´ l’est. e L’exemple suivant foreach my $v (values(%h)) { print "Valeur=$v\n"; } affichera tous les num´ros de t´l´phone (c’est-`-dire les valeurs) de la e ee a table %h. Il n’est bien sˆ r pas possible de retrouver la clef des valeurs que l’on u manipule ainsi. Il peut ˆtre int´ressant de savoir que l’ordre des clefs renvoy´es par e e e keys et celui des valeurs par values sera le mˆme a condition de ne e ` pas modifier la table de hachage entre temps. • each : it´ration sur les couples (clef,valeur) e Cette fonction renvoie un a un tous les couples (clef,valeur) d’une table ` de hachage. Elle a un comportement un peu sp´cial du fait qu’il faut e l’appeler autant de fois qu’il y a de couples : c’est une fonction avec ´tat, c’est-`-dire qu’elle ne renvoie pas toujours la mˆme chose d’un e a e appel a l’autre : en effet, elle renvoie le couple suivant ! De ce fait, je ` vous conseille de toujours l’utiliser dans la syntaxe qui suit : while( my ($k,$v) = each(%h) ) { print "Clef=$k Valeur=$v\n"; } Libre a vous de parcourir vos tables de hachage avec la fonction qui vous ` convient le mieux. 58

c sylvain@lhullier.org

Introduction a la programmation en Perl `

7.4

Autovivification

Sous ce terme barbare se cache une id´e simple : si vous tentez de modifier e un ´l´ment d’une table de hachage qui n’existe pas, il sera cr´´. S’il est ee ee utilis´ dans un contexte num´rique, il prendra pour valeur initiale z´ro. S’il e e e est utilis´ dans un contexte de chaˆ de caract`res, il prendra pour valeur e ıne e la chaˆ vide (depuis Perl 5.6). ıne Par exemple, consid´rons une table de hachage qui ne comporte pas la e clef hello ; l’expression suivante $h{hello} .= "apr`s"; e associe a la clef hello la valeur chaˆ vide puis lui concat`ne la chaˆ ` ıne e ıne "apr`s". De la mˆme fa¸on, l’expression e e c $h{bye}++; cr´e un ´l´ment de valeur 1. e ee Cette propri´t´ d’autovivification est bien pratique dans le cas o` l’on ee u ne connaˆ pas les clefs avant de devoir y acc´der. Par exemple nous allons ıt e pouvoir compter le nombre d’occurrences des mots dans un texte de mani`re e tr`s simple. Supposons que les mots du texte soient d´j` dans un tableau e ea (par exemple en utilisant la fonction qw ; elle ne r`gle pas les probl`mes des e e ponctuations, des majuscules et des lettres accentu´es, mais elle suffira a e ` notre exemple). Nous allons utiliser chaque mot comme une clef de la table et nous allons ajouter 1 a la valeur de cette clef : ` my @texte = qw( bonjour vous bonjour ); my %comptage = (); foreach my $mot ( @texte ) { $comptage{$mot}++; } while( my ($k,$v) = each(%comptage) ) { print "Le mot ’$k’ est pr´sent $v fois\n"; e } Ce qui donne l’affichage suivant : Le mot ’vous’ est pr´sent 1 fois e Le mot ’bonjour’ est pr´sent 2 fois e Dans la suite nous verrons comment d´couper un texte en mots au moyen e des expressions r´guli`res. e e 59

Introduction a la programmation en Perl `

c sylvain@lhullier.org

7.5

Existence et suppression d’une clef

` A la lecture de ce qui pr´c`de, il peut sembler impossible de savoir si e e un ´l´ment d’une table de hachage existe ou non. Rassurez-vous, les auteurs ee de Perl ont tout pr´vu :-) L’op´rateur exists renvoie vrai si l’´l´ment de e e ee table de hachage qu’on lui donne en param`tre existe ; sinon il renvoie faux. e Par exemple : if( exists( $h{hello} ) ) { print "La clef ’hello’ existe\n"; } Il est important de noter qu’un test effectu´ au moyen de l’op´rateur e e defined aurait ´t´ possible, mais dangereux. En effet, l’expression defined( ee $h{hello} ) est fausse dans deux cas tr`s diff´rents : soit si l’´l´ment n’existe e e ee pas, soit si l’´l´ment existe et vaut undef ; elle sera vraie si l’´l´ment existe ee ee et ne vaut pas undef. Il est donc impossible de distinguer le cas d’un ´l´ment ee absent et celui d’un ´l´ment ind´fini (valant undef) avec defined. ee e Cette distinction entre absent et ind´fini peut paraˆ e ıtre artificielle dans ce cas (elle peut tout de mˆme ˆtre importante dans certaines situations !), e e mais dans le cas de la suppression d’une clef, il en est tout autrement. Pour supprimer une clef dans une table de hachage, il faut utiliser l’op´e rateur delete. L’instruction delete( $h{hello} ); supprime la clef hello de la table %h si elle existe (si elle n’existe pas, elle ne fait rien). De la mˆme fa¸on que exists est la bonne m´thode pour tester e c e l’existence d’un ´l´ment, delete est la bonne m´thode pour en supprimer ee e un. Le d´butant pourrait ˆtre tent´ d’´crire : e e e e $h{hello} = undef; # attention!

Ce qui est fort diff´rent car, dans ce cas, la clef hello aura une valeur e ind´finie, mais existera toujours ! On la retrouvera, par exemple, dans les e parcours effectu´s au moyen des op´rateurs keys, values ou each ; ce qui e e n’est sans doute pas le but recherch´. e Pour r´sumer, on peut dire que pour tester l’existence d’une clef, il faut e utiliser exists et que pour en supprimer une, il faut utiliser delete. En marge de ces deux fonctions, voici une mani`re de savoir si une table e de hachage est vide ou non (on qualifie de vide une table de hachage qui ne 60

c sylvain@lhullier.org

Introduction a la programmation en Perl `

comporte aucune clef). Cette syntaxe utilise la table de hachage en contexte de chaˆ de caract`res, par exemple de cette fa¸on : ıne e c if( %h eq 0 ) { print "%h est vide\n"; } La valeur d’un hachage en contexte scalaire n’a pas d’autre utilisation que celle-ci. En effet, scalar(%A) renvoie une valeur du type 4/8 qui indique le nombre de places (buckets en anglais) utilis´es par rapport au nombre e total disponibles dans le hachage. Une table vide est un cas particulier, elle renverra 0.

7.6

Tables de hachage et listes

On peut facilement passer d’une liste (ou tableau) a une table de hachage ` et inversement. Voyez, par exemple, le petit programme suivant : my @t = ("Paul", "01.23.45.67.89", "Virginie", "06.06.06.06.06", "Pierre", "heu ..."); my %h = @t; La premi`re instruction cr´e un tableau @t initialis´ a une liste a 6 e e e ` ` ´l´ments. La seconde cr´e une table de hachage %h initialis´e au moyen ee e e du pr´c´dent tableau. Les valeurs du tableau sont prises deux a deux : la e e ` premi`re de chaque couple sera la clef dans la table de hachage, la seconde e la valeur. Si le nombre d’´l´ments de la liste est impair, la derni`re clef cr´´e ee e ee aura undef pour valeur. Si une clef venait a ˆtre pr´sente plusieurs fois dans `e e la liste, c’est la derni`re valeur qui sera prise en compte dans la table de e hachage. On aurait aussi pu ´crire : e my %h = ("Paul", "01.23.45.67.89", "Virginie", "06.06.06.06.06", "Pierre", "heu ..."); Il est a noter que cette syntaxe rappelle ´trangement l’un des premiers ` e exemple de cr´ation de table de hachage qui utilisait => pour s´parer clefs e e et valeurs. Cette similarit´ est en fait une quasi ´quivalence, car l’op´rateur e e e => peut ˆtre utilis´ a la place de la virgule pour cr´er des listes ; il n’a ´t´ e e` e ee ajout´ au langage Perl que pour faciliter la lecture des affectations de tables e 61

Introduction a la programmation en Perl `

c sylvain@lhullier.org

de hachage, car il force un contexte de chaˆ a sa gauche, ce qui permet ıne ` justement d’´crire %a = ( toto => ’titi’ ); e La conversion dans l’autre sens est aussi possible. L’´valuation d’une e table de hachage dans un contexte de liste renvoie une liste des clefs et des valeurs, se suivant respectivement deux a deux, dans un ordre quelconque ` entre couples. La table de hachage %h de l’exemple pr´c´dent peut ˆtre e e e affect´e a un tableau : e ` my @t2 = %h; Le tableau @t2 sera initialis´, par exemple, avec la liste suivante : e ("Pierre", "heu ...", "Paul", "01.23.45.67.89", "Virginie", "06.06.06.06.06") ; chaque clef pr´c`de sa valeur, mais l’ordre des couples e e (clef,valeur) est quelconque (un peu comme pour la fonction each). Une table de hachage se convertit en liste sans encombre d`s qu’elle est e en contexte de liste. Je vous laisse deviner ce que fait le code suivant : foreach my $x (%h) { print "$x\n"; } La fonction reverse, qui nous a permis d’inverser les listes, peut ˆtre e employ´e pour inverser une table de hachage : e %h = reverse(%h); Les valeurs deviennent les clefs et inversement. Si plusieurs valeurs identiques sont pr´sentes le comportement est impr´visible car, certes, lors de e e la transformation de liste en table de hachage la derni`re valeur compte, e mais lors de la transformation de table de hachage en liste l’ordre est quelconque ... L’association individu - num´ro de t´l´phone est id´ale pour illustrer e ee e cela : my %h = ("Paul", "01.23.45.67.89", "Virginie", "06.06.06.06.06", "Pierre", "heu ..."); my %quidonc = reverse %h; On pourra alors retrouver la personne a partir de son num´ro de t´l´phone. ` e ee Si, par contre, Paul et Virginie avaient eu le mˆme num´ro, on n’aurait pas e e pu pr´dire quel serait la personne renvoy´e. e e 62

c sylvain@lhullier.org

Introduction a la programmation en Perl `

7.7

Exemples

Voici quelques exemples d’utilisation des tables de hachage. Le premier concerne la variable sp´ciale %ENV qui contient les variables e d’environnement du programme. $ENV{PATH} contient le path, $ENV{HOME} vaut le nom du r´pertoire personnel de l’utilisateur qui ex´cute le proe e gramme, etc. Deuxi`me exemple, les tables de hachage peuvent servir a constituer des e ` tableaux a plusieurs dimensions ; on pourrait en effet imaginer avoir des ` clefs qui seraient la concat´nation des coordonn´es dans les n dimensions : e e dim1:dim2:dim3:... my %h = (); foreach my $i (0..4) { foreach my $j (-3..10) { foreach my $k (130..148) { $h{"$i:$j:$k"} = Calcul($i,$j,$k); } } } Nous verrons dans la suite qu’il est possible de bˆtir de r´els tableaux a a e ` plusieurs dimensions en utilisant des r´f´rences. ee L’exemple suivant concerne les ensembles ; nous allons utiliser les tables de hachage pour calculer l’union et l’intersection de deux ensembles. # Voici mes deux ensembles # Je mets les el´ments dans des tableaux ´ e my @ensA = (1, 3, 5, 6, 7, 8); my @ensB = (2, 3, 5, 7, 9); # Voici mon union et mon intersection, # les el´ments des ensembles en seront les clefs ´ e my %union = (); my %inter = (); # Je mets tous les el´ments de A dans l’union : ´ e foreach my $e (@ensA) { $union{$e} = 1; } # Pour tous les el´ments de B : ´ e foreach my $e (@ensB) { 63

Introduction a la programmation en Perl `

c sylvain@lhullier.org

# S’il est d´j` dans l’union, c’est qu’il est e a # dans A : je le mets donc dans l’intersection : $inter{$e} = 1 if ( exists( $union{$e} ) ); # Je le mets dans l’union $union{$e} = 1; } # # # # Tous sont Tous sont les des les des el´ments ´ e clefs de el´ments ´ e clefs de pr´sents e la table pr´sents e la table dans A ou B union. dans A et B inter.

# Je reconstitue des tableaux a partir ` # des tables de hachage (en les triant # pour l’affichage) my @union = sort( {$a<=>$b} keys(%union) ); my @inter = sort( {$a<=>$b} keys(%inter) ); print("@union\n"); # affiche : 1 2 3 5 6 7 8 9 print("@inter\n"); # affiche : 3 5 7 Pour le mˆme probl`me, voici une solution n’utilisant qu’une seule table e e de hachage, je vous laisse le soin d’en appr´cier le principe : e my @ensA = (1, 3, 5, 6, 7, 8); my @ensB = (2, 3, 5, 7, 9); my %hash = (); # Qu’une seule table ...

foreach my $e (@ensA) { $hash{$e}++; } foreach my $e (@ensB) { $hash{$e}++; } my @union = sort( {$a<=>$b} keys(%hash) ); my @inter = sort( {$a<=>$b} ( grep { $hash{$_}==2 } keys(%hash) ) );

64

c sylvain@lhullier.org

Introduction a la programmation en Perl `

print("@union\n"); # affiche : 1 2 3 5 6 7 8 9 print("@inter\n"); # affiche : 3 5 7 La compr´hension de cet exemple demande d’avoir assimil´ plusieurs e e notions importantes vues jusqu’ici.

65

Introduction a la programmation en Perl `

c sylvain@lhullier.org

66

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 8

Tranches
En Perl, il est possible de manipuler plusieurs ´l´ments d’un tableau ou ee d’une table de hachage a la fois. Cela s’appelle une tranche (slice en anglais). `

8.1

Tranches de tableau

Une tranche de tableau est un sous-ensemble des ´l´ments du tableau. ee Imaginons par exemple un tableau @t duquel nous souhaiterions manipuler les ´l´ments d’indice 4 et 10 ; pour cela nous allons prendre la tranche coree respondante de ce tableau : @t[4,10] est une liste a deux ´l´ments qui est ` ee ´quivalente a ($t[4],$t[10]) Quelques explications sur la syntaxe. Tout e ` d’abord, l’expression commence par une arobase, car il s’agit d’une liste d’´l´ments ; le dollar est r´serv´ aux scalaires, par exemple $t[4] est un scaee e e laire. Ensuite, comme d’habitude pour les tableaux, les crochets permettent de sp´cifier les indices. Enfin, l’ensemble des indices est indiqu´ par une liste e e d’entiers : @t[2,10,4,3] @t[3..5] @t[fonction()] ... Une telle tranche est utilisable comme valeur (passage de param`tres, e etc) et comme l-value (expression a gauche du signe ´gal d’affectation) : ` e @t[4,10] = (4321,"age"); cette instruction affecte 4321 a l’indice 4 du tableau @t et la chaˆ age ` ıne a l’indice 10. On aurait pu ´crire ` e ($t[4],$t[10]) = (4321,"age"); Un autre utilisation des tranches de tableau apparaˆ avec les fonctions ıt qui renvoient une liste. Par exemple la fonction stat prend en param`tre e 67

Introduction a la programmation en Perl `

c sylvain@lhullier.org

un nom de fichier et renvoie toute sorte d’informations sur le fichier : taille, dates, propri´taire etc. Il est courant d’´crire : e e ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename); La fonction renvoie une liste qui est affect´e aux variables de la liste e de gauche. Les tranches peuvent intervenir si seules quelques informations vous int´ressent et que vous ne voulez pas d´clarer de variables inutiles. Par e e exemple, si seules les dates de modification (indice 9) et de cr´ation (indice e 10) vous int´ressent, vous pouvez ´crire : e e ($mtime,$ctime) = ( stat($filename) )[9,10]; L’appel a la fonction est plac´ entre parenth`ses et on ne prend que les ` e e ´l´ments d’indice 9 et 10 de sa valeur de retour. On a alors une liste a deux ee ` ´l´ments, celle-ci est affect´e a la liste a gauche du signe ´gal et donc ces ee e ` ` e deux ´l´ments sont affect´s aux deux variables. ee e

8.2

Tranches de table de hachage

De la mˆme fa¸on qu’il existe des tranches pour les tableaux et les listes, e c il en existe pour les tables de hachage. La s´lection s’effectue bien sˆ r sur les e u clefs. Par exemple, si %h est une table de hachage, alors @h{’clef1’,’clef2’} est une liste ´quivalente a ($h{’clef1’},$h{’clef2’}) Il est ensuite pose ` sible d’utiliser cette liste comme bon vous semble (affectation, passage en param`tre, etc). e Une utilisation (assez complexe) des tranches serait indiqu´e lorsque l’on e veut construire automatiquement une liste de valeurs uniques a partir d’un ` tableau dont on n’est pas sˆ r que ses valeurs soient uniques : u # Un tableau avec des valeurs dupliqu´es : e my @t = qw(hello toto hello vous); # D´claration d’une table de hachage : e my %h; # On prend la tranche de %h dont les clefs # sont les valeurs du tableau @t # et on leur associe la valeur undef @h{@t} = (); 68

c sylvain@lhullier.org

Introduction a la programmation en Perl `

# Les clefs de %h sont donc constitu´es des e # valeurs de @t, et on est s^r de ne les u # retrouver qu’une seule fois : @t = keys %h; Le tableau @t comporte alors une fois et une seule chacun de ses ´l´ments. ee

69

Introduction a la programmation en Perl `

c sylvain@lhullier.org

70

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 9

Manipulation des fichiers
Pour le moment nous avons ´crit des programmes dont les interactions e avec leur environnement ´taient faibles. Nous allons voir dans cette partie e comment manipuler des fichiers en Perl. Les fichiers se retrouvent dans tous les langages, mais la mani`re tr`s simple et tr`s puissante de les manipuler e e e font des fichiers une facilit´ de Perl. e

9.1

Op´rateurs sur les noms de fichier e

Perl dispose d’op´rateurs prenant en param`tre un nom de fichier ; ce e e nom de fichier doit ˆtre un scalaire (une variable ou une constante). Leur e valeur de retour est souvent bool´enne et quelquefois num´rique. Les coutue e miers du shell retrouveront de nombreuses options de la commande test. • -e teste si son param`tre est un chemin valable dans le syst`me de e e fichier (r´pertoire, fichier, etc). On pourrait l’utiliser ainsi : e if( -e "/usr/tmp/fichier" ) { print "Le fichier existe\n"; } • -f teste si son param`tre est un fichier normal. e • -d teste si son param`tre est un r´pertoire. e e • -l teste si son param`tre est un lien symbolique. Ceci n’exclut pas que e -f ou -d renvoie vrai. • -r teste si le programme a le droit de lire le fichier/r´pertoire/etc pass´ e e en param`tre. e 71

Introduction a la programmation en Perl `

c sylvain@lhullier.org

• -w teste si le programme a le droit d’´crire. e • -x teste si le programme a le droit d’ex´cuter le fichier ou d’acc´der e e (ou ax´der :-)) au r´pertoire. e e • -o teste si le fichier appartient a l’utilisateur qui ex´cute le programme. ` e • -z teste si le fichier est vide. • -s teste si le fichier est non vide ; en fait cet op´rateur renvoie la taille e du fichier. • -M renvoie l’ˆge en jour du fichier (depuis le d´but de l’ex´cution du a e e programme). Il existe tout plein d’autres op´rateurs sur les fichiers ; pour en connaˆ e ıtre la liste complˆte, je vous invite a lancer la commande perldoc -f -X e ` Voici quelques exemple d’utilisation de ces op´rateurs : e my $file = "/usr/doc/perl"; if( -f $file && -w $file ) { .... } my $taille = -s $file; my $age = -M $file; Simple et efficace.

9.2

La fonction glob

La fonction glob prend en argument une expression et renvoie une liste de noms de fichiers. Cette liste correspond a l’´valuation de l’expression ` e selon les wildcards du shell. Par exemple, glob( ’*.o’ ) renvoie la liste des fichiers du r´pertoire e courant ayant l’extension .o Notez bien qu’il ne s’agit pas d’une expression r´guli`re (pour ceux qui e e connaissent ; pour les autres, nous en parlerons plus tard), mais bien d’une expression telle qu’on la donnerait a un shell : ls [A-Z]*.h liste tous les ` fichiers commen¸ant par une majuscule ayant l’extension .h c Il existe une syntaxe plus concise et au comportement identique a cette ` fonction : l’expression peut ˆtre mise entre chevrons. Les deux lignes suie vantes effectuent la mˆme op´ration : e e @l = glob(’/usr/include/*.h’); @l = </usr/include/*.h>; Apr`s l’ex´cution d’une de ces deux lignes, le tableau @l contient la liste e e des noms absolus des fichiers d’include pour le C du r´pertoire /usr/include e 72

c sylvain@lhullier.org

Introduction a la programmation en Perl `

9.3

Premiers exemples

Voici un premier exemple de manipulation de noms de fichiers : #!/usr/bin/perl -w use strict; foreach my $name ( <*> ) { print "$name\n" if( -l $name ); } Il affiche les liens symboliques du r´pertoire courant. e Voici un second exemple : #!/usr/bin/perl -w use strict; foreach my $name ( <.*>, <*> ) { next if( ! -d $name ); next if( ! -w $name ); print "$name : ". ( -s $name ) ."\n"; } Ce programme affiche le nom et la taille des sous-r´pertoires du r´pertoire e e courant sur lesquels j’ai les droits d’´criture (y-compris ceux commen¸ant e c par un point, donc . et ..).

9.4

Ouverture de fichier

Pour lire ou ´crire dans un fichier, il est n´cessaire de l’ouvrir pr´alablement. e e e La fonction effectuant cette op´ration en Perl se nomme open et sa syntaxe e est la suivante : open( HANDLE, expression ) Le param`tre HANDLE sera l’identifiant du fichier apr`s ouverture (on e e pourrait parler de descripteur de fichier). C’est ce descripteur qui devra ˆtre e fourni aux fonctions de lecture et d’´criture pour manipuler le fichier. Pour e ne pas rentrer trop dans les d´tails, un descripteur de fichier se repr´sente e e dans le code Perl par une simple chaˆ de caract`res (sans quotes pour ıne e la d´limiter, ni de $ pour la d´buter) ; la convention veut qu’on le mettre e e toujours en majuscules. 73

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Le param`tre expression est un scalaire (chaˆ de caract`res) compore ıne e tant le nom du fichier a ouvrir pr´c´d´ de z´ro, un ou deux caract`res indi` e e e e e quant le mode d’ouverture : Caract`re(s) e aucun < > >> +> +< Mode d’ouverture lecture lecture ´criture (´crasement) e e ´criture (ajout) e lecture et ´criture (´crasement) e e lecture et ´criture (ajout) e

Le habitu´s du shell retrouveront certaines notations connues. e Par exemple open(FIC1,"<index.html") ouvre le fichier index.html en lecture et open(FIC2,">index.html") l’ouvre en ´criture-´crasement (c’este e a-dire que le fichier sera vid´ avant que le curseur ne soit plac´ au d´but du ` e e e fichier). Cette fonction open renvoie une valeur bool´enne vrai ou faux indiquant e le bon d´roulement ou non de l’op´ration. Il est tr`s important de tester les e e e valeurs de retour des fonctions manipulant les fichiers (cela est vrai quel que soit le langage), car on ne peux jamais ˆtre sˆ r de rien. Voici deux exemples e u de tests de la valeur de retour d’open : if( ! open(FIC,">>data.txt") ) { exit(1); } Dans ce premier exemple, on tente d’ouvrir en ajout un fichier data.txt ; en cas d’impossibilit´, on appelle la fonction exit qui met fin au programme e (la valeur 1 signale une erreur ; la valeur 0 signalant la fin normal du programme, les autres valeurs sont utilis´es pour signaler au shell appelant une e erreur). Vous noterez que l’utilisateur qui ex´cute le programme n’est pas e inform´ de la cause de l’´chec ; le programme se termine, tout au plus sait-il e e qu’il y a eu un probl`me avec l’ouverture de ce fichier, mais il n’en connaˆ e ıt pas la cause. L’exemple suivant va nous permettre de lui afficher un joli message d’erreur : open(FIC2,"</tmp/$a") or die("open: $!"); Nous cherchons ici a ouvrir en lecture le fichier dont le nom serait la ` concat´nation de la chaˆ /tmp/ et du contenu de la variable $a. La fonce ıne tion die met fin au programme comme exit le ferait, mais affiche en plus 74

c sylvain@lhullier.org

Introduction a la programmation en Perl `

le param`tre qu’on lui passe. En l’occurrence, le param`tre fourni est la e e chaˆ de caract`res comportant le nom de la fonction qui cause l’´chec (on ıne e e aurait pu ajouter le nom du fichier) ainsi que la variable $!. En contexte de chaˆ de caract`res, cette variable magique $! contient le message errno de ıne e la derni`re erreur survenue, par exemple No such file or directory ou e Permission denied etc. L’utilisateur est donc inform´ de la cause de la fin e du programme. La syntaxe open() or die(); ainsi que sa signification proviennent de l’´valuation paresseuse du or. En effet, dans l’expression (a or b) si a est vrai, e il n’est pas n´cessaire d’´valuer b pour connaˆ e e ıtre la valeur de l’expression. C’est ce qu’il se passe ici : si open() renvoie vrai, il n’est pas n´cessaire e d’´valuer die(). e Les descripteurs de fichier sont d’une esp`ce ´trange en Perl, le d´butant e e e s’abstiendra de chercher a trop comprendre les m´canismes sous-jacents. ` e Ce que l’on pourrait dire, c’est qu’il n’est pas n´cessaire de d´clarer un e e descripteur de fichier, la fonction open valant d´claration. e

9.5

Lecture, ´criture et fermeture de fichier e

Une fois un fichier ouvert, il nous est possible d’´crire et/ou de lire dedans e (selon le mode d’ouverture) et de le fermer. La lecture des fichiers texte s’effectue typiquement au moyen de l’op´rae teur chevrons, cette lecture se faisant ligne par ligne. $l = <FIC>; Cette instruction lit la prochaine ligne disponible du fichier FIC. Vous noterez bien que l’op´rateur chevrons (diamond operator en anglais) est ici e en contexte scalaire. En contexte de liste, il renvoie la liste de toutes les lignes restant dans le fichier : @t = <FIC>; Cette instruction ’absorbe’ toutes les lignes du fichier dans une liste qui est plac´e dans le tableau @t. e Pour it´rer sur les lignes d’un fichier, il est courant de faire ainsi : e while( defined( $l = <FIC> ) ) { chomp $l; print "$. : $l\n"; } 75

Introduction a la programmation en Perl `

c sylvain@lhullier.org

La boucle while donne pour valeur a la variable $l une a une toutes les ` ` lignes du fichier. La fonction chomp supprime le dernier caract`re s’il s’agit e d’un retour a la ligne. La variable sp´ciale $. vaut le num´ro de la ligne ` e e courant du dernier fichier lu (ici FIC). Si vous utilisez la variable sp´ciale omni-pr´sente $_, la construction e e while( defined( $_ = <FIC> ) ) peut mˆme s’abr´ger en : e e while( <FIC> ) Pour ´crire dans un fichier, nous allons utiliser les fonctions print et e printf que nous avons d´j` vues. Elles prennent en premier argument le ea descripteur de fichier : print( FIC "toto\n" ); printf( FIC "%03d", $i ); Il faut noter qu’il n’y a pas de virgule apr`s le descripteur de fichier (il e ne faut pas en mettre !). Les parenth`ses sont comme toujours optionnelles e autour des arguments, mais permettent de lever certaines ambigu¨ es. La ıt´ fonction printf fonctionne comme printf ou fprintf du C et ne sera donc pas d´taill´e ici (voir man 3 printf). e e Pour fermer un descripteur de fichier (et donc vider les buffers associ´s), e il faut faire appel a la fonction close : ` close( FIC ); ` A noter que si vous r´utilisez un descripteur de fichier dans un open sans e faire de close au pr´alable, Perl ne rousp´tera pas et fermera consciencieue e sement le premier fichier avant d’ouvrir le deuxi`me. e Il existe plusieurs fichiers ouverts automatiquement par Perl d`s le lane cement du programme : • STDIN : l’entr´e standard (souvent le clavier). e • STDOUT : la sortie standard (souvent le terminal). Par d´faut print et e printf ´crivent sur ce flux. e • STDERR : la sortie d’erreur standard (souvent le terminal). Par d´faut e warn et die ´crivent sur ce flux. e 76

c sylvain@lhullier.org

Introduction a la programmation en Perl `

• ARGV : ce descripteur est un peu sp´cial, mais souvent bien pratique. e Les lignes lues sont celles des fichiers de la ligne de commande (donc les arguments pass´s au programme sont consid´r´s comme des noms e ee de fichier) ; si le programme est lanc´ sans argument, l’entr´e standard e e est lue. NB: vous pouvez ´crire soit <ARGV> soit <> La variable sp´ciale e e $ARGV contient le nom du fichier en cours de lecture. Discutons un peu de la manipulation de fichiers binaires. Les exemples de lecture de fichiers donn´s jusqu’ici ne conviennent pas a de tels fichiers mais e ` plutˆt a des fichiers contenant du texte. Vous pouvez, pour cela, utiliser la o ` fonction getc qui renvoie le prochain caract`re disponible : $c = getc(FIC); e Vous pouvez aussi faire usage de la fonction read qui lit un nombre d´termin´ e e de caract`res : $tailleLue = read( FIC, $tampon, $tailleALire ); Les e ` donn´es seront plac´es dans la variable $tampon A la fin du fichier, ou s’il e e y a un probl`me, le tampon n’est pas compl`tement rempli. C’est pour cela e e que l’on r´cup`re la valeur de retour de read. e e Pour ´crire des donn´es non textuelles dans un fichier, vous pouvez tout e e a fait utiliser les fonctions print et printf car les chaˆ ` ınes de caract`res de e Perl peuvent contenir le caract`re de code ASCII z´ro. On notera que la e e fonction write existe, mais n’est pas l’inverse de read. S’il vous est n´cessaire d’utiliser les fonctions d’entr´e/sortie bas niveau, e e voici leurs noms en Perl : sysopen, sysread, syswrite et close.

9.6

Deuxi`me exemple e

Voici le prolongement de l’exemple donn´ pour les tables de hachage. e Nous n’allons plus consid´rer que les mots sont contenus dans un tableau, e mais nous allons les extraire d’un fichier. #!/usr/bin/perl -w use strict; open(FILE,"<$filename.txt") or die"open: $!"; my($line,@words,$word,%total); while( defined( $line = <FILE> ) ) { @words = split( /\W+/, $line ); foreach $word (@words) { $mot =~ tr/A-Z/a-z/; $total{$word}++; 77

Introduction a la programmation en Perl ` }

c sylvain@lhullier.org

} close(FILE); foreach $word (sort keys %total) { print "$word a et´ rencontr´ $total{$word} fois.\n"; ´ e e } On effectue une boucle while sur les lignes du fichier. Chaque ligne est alors d´coup´e en mots par la fonction split (\W+ correspond aux suites de e e caract`res non-alphanum´riques, nous verrons cela dans la suite lorsque nous e e ´tudierons les expressions r´guli`res). Chaque mot est mis en minuscules au e e e moyen de l’op´rateur tr (que nous expliquerons avec les expressions r´gue e li`res). e

9.7

Ex´cution de commandes avec open e

Il est facile en Perl de lancer une commande shell et de r´cup´rer sa e e sortie standard ou de fournir son entr´e standard. e Pour lire la sortie standard d’un programme, il suffit d’utiliser la syntaxe suivante : open(HANDLE,"commande|") par exemple : open(FIC1,"ls|") open(FIC2,"df -HT $device|") Les lignes lues via le descripteur de fichier ainsi cr´´ seront celles que la ee commande aurait affich´es a l’´cran si on l’avait lanc´e depuis un terminal. e ` e e La syntaxe open(HANDLE,"|commande") permet de lancer une commande. Les lignes ´crites dans le descripteur de fichier constitueront son e entr´e standard, par exemple : e open(FIC3,"|gzip > $a.gz") open(FIC4,"|mail robert\@bidochon.org") Quoi de plus simple?

9.8

´ Ecrire une table de hachage sur disque avec les fichiers DBM

Le format DBM est un format de fichier de hachage (clef/valeur) standardis´. Il existe en dehors de Perl. e 78

c sylvain@lhullier.org

Introduction a la programmation en Perl `

En Perl, il nous est possible de manipuler directement une table de hachage en la liant avec un tel fichier : les valeurs de la table de hachage et du fichier sont synchronis´es. Pour y acc´der nous utiliserons les fonctions e e dbmopen et dbmclose Nous allons directement passer a un exemple. Il comporte deux phases : ` dans la premi`re nous allons cr´er un fichier DBM comportant un couple e e clef/valeur, dans la seconde nous utiliserons ce fichier pour retrouver ce couple. Premier script : my %h; dbmopen(%h,"data",0644) or die($!); $h{’prenom’} = ’Larry’; dbmclose(%h) or die($!); Un ensemble de fichiers data* est alors cr´´. Ces fichiers sont ensuite ee exploitables de la sorte : my %h; dbmopen(%h,"data",0644) or die($!); print "$h{’prenom’}\n"; dbmclose(%h) or die($!); Lors de cet appel a dbmopen la table %h retrouve la valeur qu’elle avait ` lors du dbmclose du premier script.

79

Introduction a la programmation en Perl `

c sylvain@lhullier.org

80

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 10

Expressions r´guli`res e e
Nous abordons ici un sujet tr`s riche en d´veloppements : les expressions e e r´guli`res. Perl en tire une partie de sa grande puissance pour l’analyse et le e e traitement des donn´es textuelles. La lecture de cette partie du document e peut aussi int´resser toute personne utilisant grep, sed, Python, PHP, C, e C++ et mˆme Java. e Atout important de Perl par rapport a d’autres langages, les expres` sions r´guli`res permettent de manipuler le texte de fa¸on tr`s puissante et e e c e tr`s concise. L’acquisition de leur maˆ e ıtrise peut s’av´rer difficile au d´but, e e mais en vaut tr`s largement la chandelle, aussi bien pour programmer en e Perl que pour utiliser les outils classiques du shell ou les autres langages pr´c´demment cit´s. e e e Au niveau vocabulaire, on utilise en anglais le terme regular expression (souvent abr´g´ en regexp voire regex), ce qui a donn´ en fran¸ais une trae e e c duction correcte ”expressions rationnelles” et une traduction mot a mot ` ”expressions r´guli`res”. La seconde est entr´e dans les mœurs et sera donc e e e utilis´e ici. e On retrouve les expressions r´guli`res dans certaines fonctions Perl que e e vous connaissez d´j`, comme par exemple split ou grep ; mais elles existent ea aussi par le biais d’op´rateurs sp´cifiques. e e

10.1

Fonctionnalit´s e

Il existe deux types principaux de fonctionnalit´s dans les expressions e r´guli`res : la correspondance (pattern matching en anglais : pattern=motif, e e matching=correspondance) et la substitution. La correspondance est le fait de tester (v´rifier) si une chaˆ de cae ıne 81

Introduction a la programmation en Perl `

c sylvain@lhullier.org

ract`res comporte un certain motif. Par exemple, on pourrait se poser les e questions suivantes et y r´pondre par un match : la variable $v commencee t-elle par un chiffre ? Comporte-t-elle au moins deux lettres majuscules ? Contient-elle une sous-chaˆ r´p´t´e deux fois d’au moins 5 caract`res ? ıne e e e e Etc. Sa syntaxe est la suivante : m/motif/ Le m indique que nous voulons faire un match, les slashes (/) servent a ` d´limiter le motif recherch´ (on verra plus loin comment utiliser d’autres e e s´parateurs). e Cette fonctionnalit´ nous permettra aussi d’extraire des sous-chaˆ e ınes d’une variable donn´e sans la modifier. Par exemple, si je veux r´cup´rer e e e le premier nombre que comporte $v, j’utiliserai aussi la correspondance. La substitution permet de faire subir des transformations a la valeur ` d’une variable. Par exemple : remplacer dans la variable $v toutes les souschaˆ ınes toto par titi. Supprimer de $v tous les mots entre guillemets. Etc. Sa syntaxe est la suivante : s/motif/chaˆne/ ı Le s indique que nous voulons faire une substitution, les slashes (/) servent a d´limiter le motif recherch´ ainsi que la chaˆ de remplacement. ` e e ıne

10.2

Bind

Pour ”lier” une variable a une telle expression, il faut utiliser l’op´rateur ` e =~ (dit bind en anglais). $v =~ m/sentier/ v´rifie si la variable $v comporte le mot sentier. On e dit alors que la variable est ”li´e” a l’expression r´guli`re. Cette expression e ` e e vaut vrai ou faux ; nous l’utiliserons donc tr`s souvent dans une structure e de contrˆle de type if : o if( $v =~ m/sentier/ ) { instructions } Dans les cas o` le test est vrai, c’est-`-dire si la variable contient le motif u a (ici si $v contient sentier), les instructions seront ex´cut´es. e e Par cette op´ration de bind, nous venons de lier une expression r´guli`re e e e a une variable. Par d´faut, une telle expression s’applique a la variable $_ ` e ` (comme beaucoup de fonctions Perl). De la mˆme fa¸on, e c $v =~ s/voiture/pieds/; 82

c sylvain@lhullier.org

Introduction a la programmation en Perl `

remplace la premi`re occurrence de voiture dans la variable $v par e pieds (on verra plus loin comment remplacer toutes les occurrences). Le reste de $v n’est pas modifi´. Le point-virgule indique la fin de l’instruction. e Pour la correspondance, il existe aussi l’op´rateur !~ qui ´quivaut a =~ e e ` suivi d’une n´gation de l’expression. e if( $w !~ m/pieds/ ) { ... } est plus concis et est ´quivalent a e ` if( ! ( $w =~ m/pieds/ ) ) { ... } Les instructions sont ex´cut´es si $w ne contient pas la chaˆ pieds. e e ıne

10.3

Caract`res e

Dans cette sous-partie et dans les suivantes, nous allons voir quels sont les motifs utilisables dans les expressions r´guli`res. e e Dans le cas g´n´ral, un caract`re vaut pour lui mˆme ; comprenez que e e e e lorsque l’on utilise l’expression r´guli`re m/a/ on v´rifie si la variable (ici e e e non cit´e) contient le caract`re a. Cela semble ´vident, mais il est bon de le e e e dire. En effet, pour certains caract`res sp´ciaux, cela n’est pas le cas. Ces e e caract`res ont un rˆle particulier dans les expressions r´guli`res (nous allons e o e e voir cela dans la suite). Si vous avez besoin de rechercher ces caract`res, il e faut donc les d´sp´cifier au moyen d’un anti-slash (\). Voici la liste de ces e e caract`res : \ | ( ) [ ] { } ^ $ * + ? . e Il faut ajouter a cette liste le caract`re choisi comme s´parateur. Pour ` e e le moment, seul le slash (/) est utilis´ dans ce document, mais nous verrons e plus tard qu’il est possible d’en changer. Par exemple $x =~ m/to\.to/ est vrai si la variable $x comporte les caract`res t o . t o contigus. e Les caract`res sp´ciaux habituels peuvent ˆtre utilis´s ; en voici quelques e e e e exemples : Motif \n \r \t \f \e Caract`re e saut de ligne retour chariot tabulation saut de page ´chappement e

Seuls les plus utiles sont pr´sent´s ici. e e 83

Introduction a la programmation en Perl `

c sylvain@lhullier.org

10.4

Ensembles

Le caract`re . (point) correspond a un caract`re quel qu’il soit (sauf e ` e \n (ce comportement peut ˆtre chang´ : nous verrons cela plus loin)). Cela e e signifie qu’` l’emplacement de ce point dans le motif pourra (devra) cora respondre un caract`re quelconque dans la variable. Par exemple, le motif e m/t.t./ reconnaˆ ıtra toute variable comportant une lettre t suivie d’un caract`re quelconque, puis une autre lettre t, puis un autre caract`re quele e conque ; par exemple toute variable comportant une des chaˆ ınes suivantes correspondra au motif : tata, t%tK, tot9 ... Vous comprenez pourquoi il faut d´sp´cifier le caract`re point avec un e e e anti-slash si vous voulez chercher un point litt´ral : sans cela un point matche e avec n’importe quel caract`re. e Le motif [caract`res] matche un caract`re parmi ceux pr´sents entre e e e crochets. Par exemple [qwerty] peut reconnaˆ une de ces six lettres. Le ıtre motif m/t[oa]t[ie]/ reconnaˆ toute variable comportant une des quatre ıtra chaˆ ınes suivantes : toti, tati, tote ou tate. On comprendra ais´ment que e si un caract`re est pr´sent plusieurs fois dans cette liste, cela a le mˆme effet e e e que s’il ´tait pr´sent une seule fois : [aeiouyie] est ´quivalent a [aeiouy]. e e e ` Il est possible de d´finir des intervalles de caract`res dans ces ensembles. e e Par exemple a-z ´quivaut aux 26 lettres minuscules de l’alphabet. Par e exemple [2a-zR] entrera en correspondance avec toute lettre minuscule ou bien avec le 2 ou bien avec le R majuscule. On peut aussi utiliser les ensembles A-Z ou 0-9 ; par extension tout intervalle est envisageable, par exemple R-Z ou toute autre combinaison tant que le num´ro ASCII du pree mier caract`re est inf´rieur a celui du second. Autre exemple, le motif [ -~] e e ` correspond a un caract`re ASCII imprimable et de num´ro inf´rieur a 127. ` e e e ` Un intervalle peut prendre place au milieu d’un motif quelconque : m/tot[a-zA0-9]V/ matche totaV, totbV ... totzV, totAV, tot0V ... tot9V. Si le caract`re tiret (-) doit ˆtre pr´sent dans l’ensemble, il faut le mettre e e e en premi`re ou en derni`re position afin de lever toute ambigu¨ e possible e e ıt´ avec un intervalle. Par exemple [a-z4-] matche soit une minuscule, soit un 4, soit un tiret. Le caract`re ^ (accent circonflexe) a un rˆle particulier s’il est plac´ en e o e d´but d’intervalle ; il prend le compl´mentaire de l’ensemble, il faut le lire e e ”tout caract`re sauf ...”. Par exemple [^ao] matche tout caract`re sauf le e e a et le o. Le motif [^0-9] matche tout caract`re non num´rique. e e Nous verrons un peu plus loin qu’il existe des raccourcis pour les ensembles les plus courants. 84

c sylvain@lhullier.org

Introduction a la programmation en Perl `

10.5

Quantificateurs

Les quantificateurs s’appliquent au motif atomique (c’est-`-dire le plus a petit possible) le pr´c´dant dans l’expression r´guli`re. Ils permettent de e e e e sp´cifier un nombre de fois o` ce motif peut/doit ˆtre pr´sent. e u e e Par exemple l’´toile * indique que le motif peut ˆtre pr´sent z´ro fois e e e e ou plus : m/a*/ se met en correspondance avec le mot vide, avec a, aa, aaa, aaaa ... Quand je dis qu’un quantificateur s’applique au motif atomique le plus petit possible, je veux dire par l` que dans l’expression r´guli`re m/za*/ a e e l’´toile s’applique uniquement a la lettre a et non au mot za. Nous verrons e ` plus loin comment faire cela. Il est par ailleurs important de noter qu’un tel quantificateur est par d´faut gourmand, c’est-`-dire qu’il se met en correspondance avec le plus e a de caract`res possible dans la variable li´e. Cela a son importance dans le e e cas d’une substitution : si la variable $v contient la chaˆ vbaaal, et si ıne on effectue l’instruction suivante : $v =~ s/ba*/hello/; la chaˆ match´e ıne e par la premi`re expression ba* sera baaa (le quantificateur matche le plus de e caract`res possible) et la substitution aura pour effet de donner pour valeur e vhellol a la variable $v. ` Voici un tableau des quantificateurs :

* + ? {n} {n,} {,n} {n,m}

le motif pr´sent e 0 fois ou plus 1 fois ou plus 0 ou 1 fois n fois exactement au moins n fois au plus n fois entre m et n fois

exemple m/a*/ m/a+/ m/a?/ m/a{4}/ m/a{2,}/ m/a{,3}/ m/a{2,5}/

mots match´s e mot vide, a, aa, aaa ... a, aa, aaa ... mot vide ou a aaaa aa, aaa, aaaa ... mot vide, a, aa ou aaa aa, aaa, aaaa ou aaaaa

On remarquera que * est un raccourci pour {0,} ainsi que + pour {1,}, de mˆme que ? pour {0,1}. e Dans les exemples pr´c´dents, tous les quantificateurs sont appliqu´s a e e e ` un caract`re. On peut les appliquer a tout motif, par exemple a un ensemble : e ` ` m/[0-9-]{4,8}/ recherche une chaˆ comportant entre 4 et 8 caract`res ıne e num´riques ou tirets contigus. e 85

Introduction a la programmation en Perl `

c sylvain@lhullier.org

10.6

Ensembles (suite)

Nous allons ici ´num´rer un certain nombre de raccourcis pour des ene e sembles courants : • \d : un chiffre, ´quivalent a [0-9] (d comme digit, chiffre en anglais) e ` • \D : un non-num´rique, ´quivalent a [^0-9] e e ` • \w : un alphanum´rique, ´quivalent a [0-9a-zA-Z_] (w comme word, e e ` c’est un caract`re d’un mot) e • \W : un non-alphanum´rique, ´quivalent a [^0-9a-zA-Z_] e e ` • \s : un espacement, ´quivalent a [ \n\t\r\f] (s comme space) e ` • \S : un non-espacement, ´quivalent a [^ \n\t\r\f] e ` On remarquera qu’un ensemble et son compl´mentaire sont not´s par la e e mˆme lettre, l’une est minuscule, l’autre majuscule. e Par exemple, l’expression r´guli`re suivante : m/[+-]?\d+\.\d+/ permet e e de reconnaˆ ıtre un nombre d´cimal, sign´ ou non : un caract`re + ou - ope e e tionnel, au moins un chiffre, un point et enfin au moins un chiffre.

10.7

Regroupement

Si dans notre exemple pr´c´dent, nous souhaitons rendre optionnelle la e e partie d´cimale, on pourrait ´crire : m/[+-]?\d+\.?\d*/ rendant ainsi none e obligatoire la pr´sence du point et celle des chiffres apr`s la virgule. Le e e probl`me de cette expression est que la pr´sence du point et de ces chiffres e e sont d´corr´l´es : l’expression r´guli`re reconnaˆ un nombre o` l’une de ces e ee e e ıtra u deux parties serait pr´sente et l’autre absente. Or ce que l’on veut, c’est que e le point et les chiffres qui le suivent soient rendus solidaires dans l’absence ou la pr´sence. e Pour cela nous allons utiliser des parenth`ses pour effectuer un regroue pement entre plusieurs motifs (ici le point et les chiffres) pour leur appliquer conjointement le mˆme quantificateur. L’expression r´guli`re e e e m/[+-]?\d+(\.d+)?/ reconnaˆ donc les nombres tels que nous les souhaiıt tons. Pour marquer la m´moire de mes ´tudiants, j’aime a leur dire que e e ` m/meuh{3}/ permet de meugler longtemps et que m/(meuh){3}/ de meugler plusieurs fois ! 86

c sylvain@lhullier.org

Introduction a la programmation en Perl `

10.8

Alternatives

Il est possible d’avoir le choix entre des alternatives ; il faut pour cela utiliser le signe pipe (|) : l’expression m/Fred|Paul|Julie/ reconnaˆ les ıt mots comportant soit Fred, soit Paul, soit Julie. De la mˆme fa¸on, l’expression m/Fred|Paul|Julie Martin/ reconnaˆ e c ıt les chaˆ ınes comportant soit Fred, soit Paul, soit Julie Martin mais rien n’oblige Fred a s’appeler Fred Martin ni Paul a s’appeler Paul Martin, ` ` comme on aurait sans doute aim´ que cela se fasse (dans ces deux derniers e cas, seul le pr´nom est reconnu, pas le nom). Pour cela, vous l’avez compris, e un regroupement est n´cessaire. L’expression r´guli`re e e e m/(Fred|Paul|Julie) Martin/ reconnaˆ les trois fr`res et soeur de la faıt e mille Martin.

10.9

Assertions

Une assertion marque une position dans l’expression, elle ne correspond a aucun caract`re (aucune ”consommation” de caract`res n’est effectu´e). ` e e e Par exemple, l’accent circonflexe (^) correspond au d´but de la chaˆ e ıne. L’expression $v =~ m/^a/ est vraie si la variable $v commence par la lettre a. Le signe ^ a donc plusieurs rˆles. S’il est au d´but d’un ensemble entre o e crochets, il permet d’en prendre le compl´mentaire ; s’il est au d´but de e e l’expression r´guli`re, il marque le d´but de la chaˆ e e e ıne. On veillera a ne pas ` les confondre. Le dollar ($) correspond a la fin de la chaˆ L’expression $v =~ m/c$/ ` ıne. est vraie si la variable $v se termine par la lettre c. Ces deux assertions sont les plus courantes. Il en existe d’autres dont \b qui marque un d´but ou une fin de mot ; c’est-`-dire entre \w et \W e a (ou entre \w et une fin ou d´but de chaˆ e ıne). Par exemple m/\btoto\b/ matche ”toto”, ”toto autreMot”, ”unMot toto autreMot”, etc. mais pas ”unMot totoMotColl´” car le deuxi`me \b ne peut pas ˆtre vrai entre la e e e lettre o et la lettre M.

10.10

R´f´rences arri`res ee e

Le regroupement au moyen des parenth`ses est dit m´morisant. Cela e e signifie que l’expression match´e par ce regroupement est gard´ en m´moire e e e 87

Introduction a la programmation en Perl `

c sylvain@lhullier.org

par le moteur d’expressions r´guli`res et qu’elle pourra servir a nouveau e e ` dans la suite de l’expression. L’exemple typique consiste a se demander si une variable contient le ` mˆme mot r´p´t´ deux fois. L’expression m/\w+.*\w+/ ne saurait nous sae e ee tisfaire ; en effet elle matche toute valeur comportant deux mots pouvant ˆtre diff´rents. La solution est d’utiliser les notations \1, \2 etc qui font e e r´f´rence aux sous-chaˆ ee ınes match´es par (respectivement) la premi`re, la e e deuxi`me, etc. expression entre parenth`ses (il n’est pas possible d’acc´der e e e a une expression au-del` de \9, mais cela nous donne d´j` une expression ` a ea tr`s lourde a g´rer). e ` e Par exemple, la r´ponse a notre probl`me de deux occurrences d’un mˆme e ` e e mot est la suivante : m/(\w+).*\1/ Le \w+ matchera un mot, les parenth`ses e m´moriseront la valeur alors trouv´e, le .* permet comme avant qu’il y ait e e un nombre ind´fini de caract`res quelconques entre les deux occurrences, e e enfin \1 fait r´f´rence a la valeur trouv´e par le \w+ pr´c´dent. ee ` e e e Autre exemple basique, m/(.+), (.+), \2 et \1/ matchera une chaˆ ıne de caract`res comportant un certain premier motif suivi d’une virgule et e d’une espace, puis un certain second motif ´galement suivi d’une virgule et e d’une espace, puis ce second motif doit ˆtre r´p´t´ suivi d’une espace, du e e ee mot et puis d’une autre espace et enfin du premier motif. Ces motifs m´moris´s sont aussi accessibles depuis le second membre e e d’une substitution au moyen des notations $1, $2 etc. Par exemple, l’instruction suivante $v =~ s/([0-9]+)/"$1"/ place des guillemets de part et d’autre du premier nombre de la variable $v : ’sdq 32sq’ deviendra ’sdq "32"sq’. Vous allez me dire : mais cela signifie que d`s que l’on fait un regroupee ment, le moteur d’expressions r´guli`res m´morise la valeur et si l’on n’utilise e e e pas certains regroupements et que d’autres sont au-del` de 9, on ne peut a donc pas s’en servir ... Je vais alors vous dire : il existe un regroupement non-m´morisant ! La notation (?:motifs) permet de regrouper les motifs e (pour leur appliquer le mˆme quantificateur par exemple) sans pour autant e qu’une m´morisation n’ait lieu. e Par exemple m/(.*) (?:et )+(.*) avec \1 \2/ matchera par exemple les valeurs suivantes : ”Paul et Julie avec Paul Julie” et ”lala et et lili avec lala lili” 88

c sylvain@lhullier.org

Introduction a la programmation en Perl `

10.11

Variables d´finies e

Ces variables sp´ciales $1, $2 etc. sont aussi accessibles apr`s l’expression e e r´guli`re (jusqu’` la fin du bloc courant ou une autre expression r´guli`re). e e a e e Elles correspondent bien sˆ r aux sous-chaˆ u ınes match´es entre parenth`ses. e e Nous pouvons nous en servir pour extraire certaines sous-chaˆ ınes et les utiliser ensuite. Il existe aussi trois autres variables, dont je vous d´conseille l’usage, mais e qui peuvent ˆtre int´ressantes : e e • $& vaut toute la sous-chaˆ matchant, ıne • $‘ vaut toute la sous-chaˆ qui pr´c`de la sous-chaˆ matchant, ıne e e ıne • $’ vaut toute la sous-chaˆ qui suit la sous-chaˆ matchant. ıne ıne Je vous d´conseille en effet l’usage de ces trois variables sp´ciales car leur e e pr´sence dans un script active pour tout le script des m´canismes particuliers e e dans le moteur d’expressions r´guli`res, qui ont pour effet secondaire d’en e e ralentir fortement la vitesse d’ex´cution. Si vous avez besoin de ces variables e dans un petit script qui ne sert qu’` cela, pas de probl`me pour les utiliser, a e mais ´vitez leur usage dans un projet de plusieurs milliers de lignes ou dans e un script CGI appel´ 10 fois par seconde. e Voici un exemple : my $v = "za aa et tfe"; if( $v =~ /(a+) et ([a-z])/ ) { print "$1\n"; # ’aa’ print "$2\n"; # ’t’ print "$&\n"; # ’aa et t’ print "$‘\n"; # ’za ’ print "$’\n"; # ’fe’ } Il est bon de savoir que cela est possible sans obligatoirement se souvenir du nom de toutes les variables.

10.12

Valeurs de retour de m//

Je vous ai dit jusqu’ici que l’op´rateur de correspondance m// retournait e vrai ou faux ; cela est exact en contexte scalaire. C’est par exemple le cas lorsqu’on ´crit : e if( $w =~ m/motif/ ) 89

Introduction a la programmation en Perl ` { ... }

c sylvain@lhullier.org

On parle alors de correspondance. Mais en contexte de liste, cet op´rateur retourne la liste des ´l´ments e ee match´s entre parenth`ses (les fameux $1, $2 etc, et cela sans limite a 9). e e ` Par exemple : ($x,$y) = ( $v =~ m/^(A+).*(B+)$/ ); place dans $x les caract`res A du d´but de la chaˆ $v et dans $y la e e ıne suite de caract`res B terminant la chaˆ e ıne. On parle ici d’extraction. Il se peut tout a fait que cette op´ration ´choue (en cas d’absence des ` e e lettres aux endroits attendus par exemple). Cet usage peut ˆtre combin´ e e avec l’utilisation d’un test. On peut en effet ´crire : e if( ($x,$y) = ( $v =~ m/^(A+).*(B+)$/ ) ) { ... } auquel cas, on n’ex´cute les instructions du if que si $v comporte au e moins un A en son d´but et un B a sa fin. Dans ce cas, les variables $x et $y e ` re¸oivent les valeurs entre parenth`ses. On a alors combin´ correspondance c e e et extraction.

10.13

Exemples de probl`mes e

Dans cette partie, je vais vous pr´senter diff´rents petits exercices prae e tiques sur les expressions r´guli`res. Les solutions se trouvent un peu plus e e loin. Essayez de ne pas vous pr´cipiter pour les lire, prenez le temps de e chercher dans ce qui pr´c`de ce qu’il vous faut pour r´soudre les probl`mes. e e e e Que font les instructions suivantes? • if( $v =~ m/\w+ \d* ?:/ ) { ... } • if( $v =~ m/^"([a-z]{4,})",/ ) { print "$1\n"; } • if( $v =~ m/([a-z]+)[a-z]*\1/ ) { print "$1\n"; } • ($n,$m) = ( $v =~ m/(\w+)=(\d+)/ ); • if( ($n,$m) = ( $v =~ m/(\w+)=(\d+)/ ) ) { print "$n $m\n"; } • $v =~ s/^ServerRoot/DocumentRoot/; 90

c sylvain@lhullier.org

Introduction a la programmation en Perl `

• $v =~ s/^C="([^"]*)"/D=’$1’/; • $v =~ s/ +/ /; ´ Ecrivez les instructions r´alisant les actions suivantes : e • V´rifier que $v comporte velo. e • V´rifier que $v finit par une lettre majuscule. e • V´rifier que $v comporte deux fois de suite un mˆme nombre (s´par´es e e e e par un signe d’op´ration math´matique). e e • Extraire de $v chacun des deux premiers caract`res. e • Extraire de $v les deux premiers mots. • Extraire de $v le dernier caract`re non-num´rique. e e • Remplacer dans $v rouge par bleu. • Supprimer de $v les espaces en fin de chaˆ ıne. • Supprimer les guillemets autour du nombre entier de $v. Je rel`ve les copies dans 30 minutes ;-))) e

10.14

Solutions des probl`mes e

Voici les solutions de la premi`re partie des probl`mes : e e • if( $v =~ m/\w+ \d* ?:/ ) { ... } On v´rifie que $v comporte un mot d’une lettre ou plus (\w+) suivi e d’une espace, puis ´ventuellement d’un nombre (\d*), puis d’une ese pace optionnelle ( ?) et enfin du signe deux-points. Si c’est le cas, les instructions du if sont ex´cut´es. e e • if( $v =~ m/^"([a-z]{4,})",/ ) { print "$1\n"; } On v´rifie que $v commence par un guillemet, suivi d’au moins quatre e lettres minuscules (que l’on m´morise), d’un autre guillemet puis d’une e virgule. Si la variable est du bon format, ces quatre lettres (ou plus) sont affich´es. e • if( $v =~ m/([a-z]+)[a-z]*\1/ ) { print "$1\n"; } On recherche quelque chose de la forme : une suite de caract`res en e minuscules (au moins 1) puis une deuxi`me suite de caract`res en e e minuscules (´ventuellement aucun) et enfin la mˆme suite de caract`res e e e 91

Introduction a la programmation en Perl `

c sylvain@lhullier.org

• •

que la premi`re suite. On cherche donc un mot (suite de lettres) dont e un certain nombre de lettres se r´p`tent. Si la variable $v comporte e e un tel mot, on affichera ces lettres r´p´t´es. e ee ($n,$m) = ( $v =~ m/(\w+)=(\d+)/ ); On recherche une suite alphanum´rique, un signe ´gal puis un nombre. e e Il s’agit d’une affectation. La variable et le nombre sont respectivement affect´s aux variables $n et $m. e if( ($n,$m) = ( $v =~ m/(\w+)=(\d+)/ ) ) { print "$n $m\n"; } Si la variable $v est du format pr´c´demment cit´, on affiche la variable e e e et le nombre de l’affectation. $v =~ s/^ServerRoot/DocumentRoot/; On remplace ServerRoot par DocumentRoot s’il est en d´but de chaˆ e ıne. $v =~ s/^C="([^"]*)"/D=’$1’/; On recherche en d´but de chaˆ une sous-chaˆ C="motif" dont motif e ıne ıne ne comporte pas de ". Tout cela est remplac´ par D=’motif’ o` motif e u est inchang´. e $v =~ s/ +/ /; Remplace dans $v la premi`re suite d’espaces par une seule espace. e

Voici les solutions de la seconde partie des probl`mes : e • V´rifier que $v comporte velo. e Pas trop dur : il s’agit d’un simple match. if( $v =~ m/velo/ ) { ... } • V´rifier que $v finit par une lettre majuscule. e Match ici aussi. Le dollar nous permet de nous ”accrocher” en fin de chaˆ : ıne if( $v =~ m/[A-Z]$/ ) { ... } • V´rifier que $v comporte deux fois de suite un mˆme nombre (s´par´es e e e e par un signe d’op´ration math´matique). e e Encore un match. Nous cherchons un nombre \d+ que nous m´morisons e (parenth`ses). Un signe doit suivre (il faut d´sp´cifier le signe de la e e e 92

c sylvain@lhullier.org

Introduction a la programmation en Perl `

division car il est aussi le s´parateur de l’expression r´guli`re). Finae e e lement le mˆme nombre qu’avant doit ˆtre pr´sent (\1) : e e e if( $v =~ m/(\d+)[+*\/-]\1/ ) { ... } • Extraire de $v chacun des deux premiers caract`res. e Nous allons utiliser un match pour faire de l’extraction : on se place en d´but de chaˆ avec ^, on prend un caract`re avec . que l’on e ıne e m´morise, puis de la mˆme fa¸on pour le deuxi`me. Vous noterez que, e e c e dans ce cas, l’usage de la fonction substr est possible (et indiqu´ ...) e ($prem,$deux) = ( $v =~ m/^(.)(.)/ ); • Extraire de $v les deux premiers mots. La m´thode est la mˆme que pour l’exemple pr´c´dent. Le seul point e e e e un peu d´licat a voir, c’est qu’entre deux mots (\w+), il doit forcement e ` y avoir des caract`res ”non-mot” (\W+) : e ($prem,$deux) = ( $v =~ m/^\W+(\w+)\W+(\w+)/ ); • Extraire de $v le dernier caract`re non-num´rique. e e De la mˆme fa¸on, apr`s le dernier caract`re non-num´rique, il n’y a e c e e e que des num´riques (z´ro ou plus), le dollar pour se placer a la fin de e e ` la chaˆ : ıne ($c) = ( $v =~ m/(\D)\d*$/ ); • Remplacer dans $v rouge par bleu. Facile (seule la premi`re occurrence est remplac´e) : e e $v =~ s/rouge/bleu/; • Supprimer de $v les espaces en fin de chaˆ ıne. On va remplacer tous ces espaces par rien : $v =~ s/ +$//; • Supprimer les guillemets autour du nombre entier de $v. On va faire une substitution, en m´morisant ce fameux nombre : e $v =~ s/"(\d+)"/$1/; Les fonctionnalit´s les plus importantes ont ´t´ abord´es vous voila par´s e ee e e pour la suite des op´rations. Voici d’autres fonctionnalit´s plus pouss´es et e e e donc plus int´ressantes. Les quantificateurs non-gourmands et surtout les e options sont des points importants. 93

Introduction a la programmation en Perl `

c sylvain@lhullier.org

10.15

Choisir son s´parateur e

Il est tout a fait possible de choisir un autre caract`re que le slash (/) e comme s´parateur. Il se peut par exemple que nous ayons a manipuler des e ` URL ; dans ce cas, le caract`re slash fait partie des motifs que l’on est suse ceptible de rechercher ; il est de ce fait fort fastidieux de devoir d´sp´cifier e e chaque slash utilis´, comme par exemple dans l’expression suivante (ici une e version simplifi´e de l’expression r´guli`re qui reconnaˆ les URL) : e e e ıt if( $v =~ m/http:\/\/\w+/(\w+\/)*\w\.html/ ) Il serait plus lisible de prendre un autre s´parateur, le signe ´gal par e e exemple : if( $v =~ m=http://\w+/(\w+/)*\w\.html= ) La plupart des caract`res est utilisable comme s´parateur. e e Si vous utilisez le slash comme s´parateur, la lettre m n’est pas obligatoire e pour faire un match : $v =~ /velo/ est ´quivalent a $v =~ m/velo/ e ` Libre a vous de choisir le bon s´parateur, sachant que dans la grande ` e majorit´ des cas le slash est utilis´. e e

10.16

Options

Apr`s le dernier s´parateur des op´rateurs de correspondance (m ou rien) e e e ou de substitution (s) il est possible d’indiquer une ou plusieurs options. Les syntaxes sont donc : m/motif/options et s/motif1/motif2/options Les options permettent de modifier le comportement du moteur d’expressions r´guli`res. Voici la liste de quelques options parmi les plus utiles : e e • L’option i rend le motif insensible a la case (minuscules/majuscules) : ` l’expression r´guli`re m/toto/i recherche le mot toto indiff´remment e e e en majuscules ou en minuscules. On aurait pu ´crire e m/[tT][oO][tT][oO]/ • L’option g permet d’effectuer toutes les substitutions dans la variables. Par d´faut, l’op´rateur s/// effectue la transformation de la premi`re e e e occurrence du motif recherch´ et ne va pas plus loin. Si cette option est e sp´cifi´e, le moteur d’expressions r´guli`res avancera dans la variable e e e e tant qu’il pourra y faire des substitutions. Par exemple, l’expression $v =~ s/ +/ /g; remplace chaque groupe de plusieurs espaces par une seule (contrairement a un des exercices ` 94

c sylvain@lhullier.org

Introduction a la programmation en Perl `

pr´c´dents o` l’expression r´guli`re ne rempla¸ait que la premi`re oce e u e e c e currence du motif trouv´). e Voyez par exemple le code suivant : $t = $s = "sd et sd"; $t =~ s/sd/toto/; # => "toto et sd" $s =~ s/sd/toto/g; # => "toto et toto" L’option g est aussi utilisable en correspondance. Elle permet a cet ` op´rateur de fonctionner avec ´tat, c’est-`-dire de poursuivre sa ree e a cherche en partant du dernier motif trouv´. On l’utilise typiquement e dans une boucle ; voyez cet exemple : my $v = "aatobbtbvvtczz"; while( $v =~ m/t./g ) { print "$&\n"; } L’affichage effectu´ est le suivant : e to tb tc • Dans une substitution, l’option e ´value le membre de droite comme e une expression Perl, et remplace le motif trouv´ par la valeur de cette e expression. Par exemple : $s =~ s/(\d+)/fonction($1)/e; remplace le premier nombre trouv´ dans la variable $s par la valeur e de retour de la fonction appliqu´e a ce nombre. e ` Autre exemple, avec des options combin´es celui-l` : e a $s =~ s/0x([0-9a-f]+)/hex($1)/gei; transforme tous les nombres hexad´cimaux en nombres d´cimaux dans e e la variable $s. • L’option o a pour effet qu’une seule compilation de l’expression r´guli`e e re a lieu. En temps normal, a chaque fois que l’interpr´teur Perl passe ` e sur une expression r´guli`re, il la compile (pour ceux qui connaissent, e e 95

Introduction a la programmation en Perl `

c sylvain@lhullier.org

il construit l’automate) ; avec cette option, la compilation a lieu une seule fois lors de la premi`re ex´cution. Le principal avantage est un e e temps d’ex´cution plus court pour le programme, si cette expression e est utilis´e plusieurs fois. Les inconv´nients sont une place m´moire e e e occup´e (inutilement si l’expression r´guli`re ne sert que peu de fois) e e e et que, si le motif peut changer (voir la suite concernant les variables dans les motifs), ce changement ne sera pas pris en compte. Il existe deux options (exclusives l’une de l’autre) qui permettent de changer certains comportements sur les d´buts et fins de chaˆ e ınes. Pour les exemples qui suivent, je pose $s = "mot\nlu"; : • Par d´faut : mode interm´diaire. e e • Les caract`res ^ $ se positionnent en d´but/fin de chaˆ e e ıne. Par exemple ($s=~m/mot$/) est faux. • Le caract`re . ne matche pas \n. Par exemple ($s=~m/t.lu$/) e est faux. • Avec l’option s : on travaille en ligne unique. • Les caract`res ^ $ se positionnent en d´but/fin de chaˆ e e ıne. Par exemple ($s=~m/mot$/s) est faux. • Le caract`re . peut matcher \n. Par exemple ($s=~m/t.lu$/s) e est vrai. • Avec l’option m : on travaille en ligne multiple. • Les caract`res ^ $ se positionnent en d´but/fin de ligne. Par e e exemple ($s=~m/mot$/m) est vrai. • Le caract`re . ne matche pas \n. Par exemple ($s=~m/t.lu$/m) e est faux.

10.17

Quantificateurs non-gourmands

Posons-nous le probl`me suivant. Nous avons une chaˆ de la forme e ıne "s ’r’ g ’e’ y" de laquelle nous souhaitons extraire les chaˆ ınes qui sont entre guillemets. La premi`re id´e est d’´crire quelque chose comme : /’.*’/ e e e ce qui n’est pas satisfaisant, car dans notre exemple la chaˆ ’r’ g ’e’ ıne serait match´e. En effet, je vous avais dis que les quantificateurs consomment e 96

c sylvain@lhullier.org

Introduction a la programmation en Perl `

le plus de caract`res possible, nous voici dans une illustration du ph´nom`ne. e e e On parle de quantificateurs gourmands, gloutons, avides ou greedy en anglais. Il existe des quantificateurs dont le comportement est, au contraire, de consommer le moins de caract`res possible. On parle alors de quantificateurs e non-gourmands, ´conomes ou frugaux. Leur notation est la mˆme que celle e e des quantificateurs que vous connaissez mais suivie d’un point d’interrogation : Gourmand * + ? {n,m} Non gourmand *? +? ?? {n,m}?

Pour revenir a notre exemple, on peut ´crire /’.*?’/ et la correspon` e dance sera effectu´e telle que nous la souhaitions. e Vous allez me dire, car vous avez tout compris aux expressions r´guli`res e e ;-) , qu’il est possible de faire cela sans utiliser ces quantificateurs nongourmands. Dans notre exemple, on peut tout a fait ´crire : /’[^’]*’/ ce qui ` e permet de ne pas accepter de guillemets entre les guillemets. Je r´pondrais e que je suis d’accord avec vous. Mais voici un autre exemple o` les quantificateurs non-gourmands nous u sauvent la mise. Si cette fois la chaˆ a pour valeur ıne "s STARTrSTOP g STARTe fSz zSTOP y" et que nous souhaitons extraire les sous-chaˆ ınes plac´es en les marqueurs START et STOP, il nous est fort ais´ e e d’´crire : /START.*?STOP/ e

10.18

Substitution de variables dans les motifs

Il est tout a fait possible de mettre une variable dans un motif d’une ` expression r´guli`re. Cette variable sera substitu´e par son contenu. Par e e e exemple : $s = "velo"; if( $v =~ m/$s$/ ) { ... } La variable sera substitu´e et la recherche s’effectuera sur le mot velo en e fin de chaˆ ; le premier dollar concerne la variable $s, le second marque la ıne fin de chaˆ ıne. Perl sait automatiquement si un $ correspond a une variable ` ou a la sp´cification ”fin de chaˆ ` e ıne”. Il est ainsi possible de rechercher la 97

Introduction a la programmation en Perl `

c sylvain@lhullier.org

valeur d’une variable dans une autre. La mˆme chose est possible avec la e substitution, aussi bien pour le premier membre que pour le second. Notez cependant que si la variable substitu´e contient des caract`res e e sp´ciaux au sens des expressions r´guli`res, ils seront vus comme tels. Si e e e dans notre exemple, la variable $s avait pour valeur la chaˆ ”ve(lo”, le ıne moteur d’expression r´guli`re nous signalerait une erreur due a la parenth`se e e ` e ouvrante qui n’est pas referm´e, exactement comme si nous avions ´crit : e e if( $v =~ m/ve(lo$/ ) { ... } # incorrect

Cela peut aussi poser des probl`mes de s´curit´ si le programmeur ne e e e sait pas ce que peut contenir la variable substitu´e (par exemple si sa valeur e provient de l’utilisateur). Il existe pour cela une fonction quotemeta qui prend en param`tre une chaˆ de caract`res et renvoie cette mˆme chaˆ e ıne e e ıne en ayant d´sp´cifi´ les caract`res sp´ciaux. e e e e e $s = "fds(ds"; $s2 = quotemeta($s); print "$s2\n"; # affiche if( $v =~ m/$s2/ ) { ... }

fds\(ds

Pensez a toujours utiliser cette fonction lorsque vous voulez placer une ` variable dans un motif ; cela r´sout bien des probl`mes. e e

10.19

Op´rateur tr e

Cet op´rateur ne concerne pas vraiment les expressions r´guli`res, mais e e e il en est proche. Mettez de cˆt´ ce que vous venez d’apprendre sur celles-ci oe pour lire la suite. tr est un op´rateur de translation lettre a lettre (on parle de transe ` litt´ration). Voici sa syntaxe : tr/chaˆne1/chaˆne2/ ou encore e ı ı y/chaˆne1/chaˆne2/ ı ı Les deux chaˆ ınes doivent ˆtre de la mˆme longueur car cet op´rateur va e e e remplacer la premi`re lettre de la premi`re chaˆ par la premi`re lettre de e e ıne e la seconde chaˆ ıne, la deuxi`me lettre de la premi`re chaˆ par la deuxi`me e e ıne e lettre de la seconde chaˆ ıne, etc. Cette transformation a lieu sur la variable li´e ou sur $_ par d´faut. e e Voici un petit exemple : $s = "azerty"; $s =~ tr/abcde/01234/; print "$s\n"; # affiche 0z4rty 98

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Dans la variable $s, tous les a seront transform´s en 0, tous les b en 1, e etc, tous les e en 4 etc. Il est possible d’utiliser des intervalles : $s =~ tr/a-z/A-Z/; met par exemple le contenu de la variable en majuscules. C’est l’un des seuls usages courants de l’op´rateur tr. e

10.20

Un dernier mot sur les expression r´guli`res e e

Les expressions r´guli`res sont un outil tr`s puissant. Les maˆ e e e ıtriser ouvre des portes au programmeur. Certes, il est souvent difficile de rentrer dans le jeu, mais cet effort est r´compens´ par de nouvelles possibilit´s inimaginables e e e avant. Les expressions r´guli`res de Pel sont si puissantes et bien pens´es que e e e de nombreux langages les impl´mentent, en se vantant d’ˆtre perl5-regexes e e compliant ! On peut, par exemple, citer la librairie pcre du langage C, dont le nom provient des initiales de ”Perl-compatible regular expressions” ... Sachez aussi que toutes les fonctionnalit´s des expressions r´guli`res e e e n’ont pas ´t´ trait´es ici. Les plus courantes ou importantes le sont, mais ee e il en existe d’autres encore ... Sachez de plus que les expressions r´guli`res, e e c’est bien, mais il faut savoir quand les utiliser et quand ne pas les utiliser.

99

Introduction a la programmation en Perl `

c sylvain@lhullier.org

100

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 11

R´f´rences ee
Les r´f´rences permettent de bˆtir des structures complexes et comee a pos´es : tableau de tableaux ou de tables de hachage et inversement, table e de hachage de tableaux ou de tables de hachage ... Le terme de r´f´rence en Perl correspond a peu pr`s a celui de pointeur ee ` e ` en C et C++ et a celui de r´f´rence en Java. Les habitu´s du C ou C++ ` ee e noterons que les calculs sur r´f´rences sont interdits en Perl, ce qui permet ee d’´viter toutes sortes de probl`mes dus a des acc`s m´moire erron´s (plus e e ` e e e de Segmentation fault). Chaque variable, qu’elle soit scalaire, tableau ou table de hachage, est pr´sente a une position donn´e dans la m´moire. Une r´f´rence vers une e ` e e ee variable est (sch´matiquement) l’adresse m´moire de cette variable. Une e e telle r´f´rence peut elle-mˆme ˆtre stock´e dans une variable scalaire. ee e e e

11.1

R´f´rences sur scalaire ee

L’op´rateur qui permet de prendre la r´f´rence d’une variable est l’antie ee slash (\) : \$v est la r´f´rence de la variable $v ee my $refv = \$v;

Ici la variable $refv (on aurait pu choisir un tout autre nom pour cette variable) est une r´f´rence vers la variable $v. Une variable de type r´f´rence, ee ee quelque soit celui de la variable qu’elle r´f´rence (scalaire, tableau ou table ee de hachage), est un scalaire. On peut repr´senter la relation entre ces deux e 101

Introduction a la programmation en Perl ` variables de la fa¸on suivante : c

c sylvain@lhullier.org

$refscalaire $v −43.5
La variable $refv contient l’adresse de la variable $v (ainsi que l’information consistant a savoir que $v est une variable scalaire). On dit que ` $refv pointe vers $v, car on va pouvoir manipuler $v (l’afficher, la modifier etc) en utilisant $refv ; on repr´sente ce lien par une fl`che de $refv vers e e $v. Il nous est alors possible de manipuler $v au travers de $refv. La notation $$refv (donc avec deux dollars) est ´quivalente a $v tant que $refv e ` pointe vers $v. Autrement dit, la notation $$refv ´quivaut a la variable e ` scalaire point´e par la r´f´rence $refv. Dit de mani`re plus prosa¨ e ee e ıque, on va acc´der a la variable qu’il y a ”au bout” de la r´f´rence (au bout de la e ` ee fl`che du sch´ma). On dit alors que l’on d´r´f´rence la variable $refv. Pour e e e ee faire un parall`le avec le langage C, il s’agit de l’´quivalent de l’´toile (*) e e e appliqu´e a un pointeur. e ` Revenons sur notre exemple. Nous d´clarons une variable scalaire $v que e nous initialisons. Nous d´clarons ensuite une autre variable scalaire $refv a e ` laquelle on affecte l’adresse de $v ; $refv est donc une r´f´rence sur $v : ee my $v = -43.5; my $refv = \$v; On affiche la valeur de la r´f´rence : ee print "$refv\n"; # affiche SCALAR(0x80ff4f0)

On voit bien alors que la r´f´rence pointe vers une variable de type scaee laire (SCALAR) dont l’adresse m´moire est affich´e en hexad´cimal. Affichons e e e maintenant la variable point´e par $refv (c’est-`-dire $v ici) : e a print "$$refv\n"; # affiche -43.5

L’affichage effectu´ est -43.5 (c’est-`-dire la valeur de $v). Cette notae a tion $$refv est ´quivalente a $v puisque $refv est une r´f´rence sur $v. e ` ee Cette ´quivalence vaut aussi bien lorsque l’on a besoin de la valeur de $v e (affichage etc) que lorsque l’on veut affecter une nouvelle valeur a $v : ` $$refv = 56; # affecte 56 a $v ` 102

c sylvain@lhullier.org

Introduction a la programmation en Perl `

On affecte 56 a $$refv, c’est-`-dire a $v. Si on affiche cette variable, on ` a ` voit bien qu’elle contient cette nouvelle valeur : print "$$refv\n"; print "$v\n"; # affiche 56 # affiche 56

Rien de bien sorcier.

11.2

Utilisation des r´f´rences sur scalaire ee

` A quoi peut bien servir une r´f´rence sur un scalaire? Par exemple a le ee ` modifier dans une fonction : sub f { my ($ref) = @_; $$ref = 0; } Cette fonction prend en argument une r´f´rence et affecte 0 a la variable ee ` scalaire point´e par cette r´f´rence. On pourrait l’utiliser ainsi : e ee f( $refv ); Ce qui aurait pour effet de mettre la variable $v a la valeur 0. On pourrait ` aussi ´crire directement : e f( \$v ); Voici un autre exemple simple d’utilisation des r´f´rences : ee sub f2 { my $w = 43; return \$w; } Cette fonction f2 d´clare une variable locale $w et renvoie une r´f´rence e ee vers cette variable. Contrairement a ce qu’il se passe en C, ceci est tout a ` ` fait l´gal et sans risque en Perl. Voici comment utiliser cette fonction : e my $reff = f2(); 103

Introduction a la programmation en Perl `

c sylvain@lhullier.org

La variable scalaire $reff devient donc une r´f´rence vers une variable ee scalaire valant 43. Cette variable scalaire valant 43 est l’ancienne variable $w de la fonction f2. La variable $reff pointe donc vers une variable qui n’a plus de nom : dans f2 elle s’appelait $w, mais en dehors de l’appel a cette ` fonction qui l’a cr´´e, elle n’a plus de nom. ee

$reff 0
En temps normal, une variable locale a une fonction est d´truite lorsque ` e l’on sort de la fonction. Mais tant qu’il existe une r´f´rence vers la variable, ee elle est conserv´e en m´moire. C’est le garbage-collector (ramasse-miette e e ou glaneur de cellules) qui la lib´rera lorsque plus aucune r´f´rence sur la e ee variable n’existera. Il faut noter que lors d’un prochain appel a la fonction f2, une autre va` riable $w sera cr´´e ind´pendante de la premi`re ; il n’y aura donc pas d’effet ee e e de bord sur la premi`re r´f´rence renvoy´e. Nous sommes ici en pr´sence e ee e e d’une fonction qui peut faire office de g´n´rateur de r´f´rences sur scalaire e e ee ;-)

11.3

R´f´rences sur tableau ee

Il est possible de cr´er une r´f´rence sur un tableau. L’op´rateur qui e ee e permet cela est le mˆme que pour les scalaires ; il s’agit de l’anti-slash (\) e appliqu´ a une variable de type tableau : e` my @t = (23, "ab", -54.4); my $reft = \@t; La variable scalaire $reft est donc une r´f´rence vers le tableau @t : ee $reft @t

0

23

1

ab

2

−54.4

Pour d´r´f´rencer une telle r´f´rence, il convient d’utiliser une arobase eee ee (@) : @$reft est ´quivalent a @t. On peut ainsi utiliser la valeur de @t en e ` utilisant $reft : my @t2 = @$reft; 104

c sylvain@lhullier.org

Introduction a la programmation en Perl `

foreach my $e (@$reft) { .... } On peut aussi modifier @t de la sorte : @$reft = (654.7, -9, "bonjour"); Si, pour acc´der au i`me ´l´ment de @t, il ´tait possible d’´crire $t[i], il e e ee e e est maintenant possible d’´crire $$reft[i]. On peut alors dire, de mani`re e e sch´matique et pour fixer les choses, que la notation $reft est ´quivalente e e au nom t de la variable dans toute les syntaxes utilisant ce tableau (partout o` l’on peut ´crire t, on peut ´crire $reft a la place, tant que $reft pointe u e e ` sur @t). Voici, en effet, un r´capitulatif des ´quivalences de notations : e e Tableau t @t $t[i] $t[i] R´f´rence ee $reft @$reft $$reft[i] $reft->[i]

Cette derni`re notation $reft->[i] est ´quivalente a $$reft[i] et core e ` respond donc au i`me ´l´ment du tableau r´f´renc´ par $reft. C’est la e ee ee e notation la plus souvent utilis´e pour cela ; elle rappelle la mˆme notation e e fl`che (->) du langage C. e L’expression $reft->[1] = "coucou"; affecte donc a l’´l´ment d’indice 1 du tableau point´ par $reft une ` ee e nouvelle valeur. Munis des r´f´rences, il va maintenant nous ˆtre possible de cr´er des ee e e tableaux de tableaux. Cela ´tait pour le moment impossible en raison de e l’aplatissement des listes. Une r´f´rence ´tant un scalaire, il va nous ˆtre ee e e possible de stocker une r´f´rence comme valeur dans un tableau : ee my @t1 = ( 16, -33 ); my @t2 = ( "el", 0.3, 4 ); my @t = ( 6, \@t1, \@t2, "s" ); Le tableau @t comporte donc un premier ´l´ment valant 6, un deuxi`me ee e ´tant une r´f´rence vers un tableau a deux ´l´ments, un troisi`me une e ee ` ee e r´f´rence vers un tableau a trois ´l´ments et enfin un ´l´ment valant la ee ` ee ee chaˆ "s". ıne 105

Introduction a la programmation en Perl ` Ce qui peut se repr´senter sous la forme suivante : e

c sylvain@lhullier.org

@t 0 6 1 2 3 s

0

el

1

0.3

2

4

0

16

1

−33

Vous noterez bien que la syntaxe suivante correspond a la cr´ation d’un ` e tableau a sept ´l´ments (aplatissement des listes) : ` ee my @t2 = ( 6, ( 16, -33 ), ( "el", 0.3, 4 ), "s" ); Nous verrons dans la suite d’autres syntaxes pour construire des tableaux de tableaux.

11.4

R´f´rences sur table de hachage ee

De la mˆme fa¸on que pour les scalaires et pour les tableaux, la cr´ation e c e d’une r´f´rence vers une table de hachage utilise l’op´rateur anti-slash (\) : ee e my %h = ( ’Paul’ => 21, ’Julie’ => 19 ); my $refh = \%h; La variable scalaire $refh est donc une r´f´rence vers la table de hachage ee %h :

$refh %h Julie Paul => => 19 21

106

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Pour d´r´f´rencer une r´f´rence vers une table de hachage, il faut utiliser eee ee le caract`re pourcentage (%) ; %$refh est ´quivalent a %h : e e ` my %h2 = %$refh; foreach my $k (keys %$refh) { ... } Les deux notations suivantes permettent d’acc´der a la valeur associ´e e ` e a la clef Paul : $$refh{Paul} et $refh->{Paul} sachant que la seconde est ` la plus utilis´e pour des raisons identiques aux cas des tableaux. e $refh->{Jacques} = 33; Voici un r´capitulatif des ´quivalences : e e Hash h %h $h{Paul} $h{Paul} R´f´rence ee $refh %$refh $$refh{Paul} $refh->{Paul}

Voici une fa¸on d’afficher tous les couples clef/valeur de la table de hac chage r´f´renc´e par $refh : ee e foreach my $k (keys %$refh) { print "$k $refh->{$k}\n"; } Cette notation fl`che rend l’expression plutˆt lisible. e o

11.5

R´flexions ` propos des r´f´rences e a ee

On a vu que pour d´r´f´rencer une r´f´rence vers un scalaire on utilise eee ee le caract`re dollar ($), vers un tableau le caract`re arobase (@) et vers une e e table de hachage le caract`re pourcentage (%). Mais que se passerait-il s’il e nous venait a l’id´e de ne pas choisir le bon caract`re de d´r´f´rencement, ` e e eee par exemple d’utiliser le dollar pour une r´f´rence sur tableau ou bien le ee pourcentage pour une r´f´rence sur scalaire ? N’arriverons-nous pas a des ee ` incoh´rences comme en C? e 107

Introduction a la programmation en Perl `

c sylvain@lhullier.org

La r´ponse est non, car l’interpr´teur veille au grain. Il refusera de e e consid´rer comme un tableau une variable scalaire par exemple. En cas d’ine compatibilit´ de type, un de ces trois messages sera affich´ lors de l’ex´cution e e e et le programme prendra fin : Not a SCALAR reference at script.pl line 23. Not an ARRAY reference at script.pl line 23. Not a HASH reference at script.pl line 23. Comme une r´f´rence peut pointer vers n’importe quel type de structure ee (scalaire, tableau, table de hachage), cette v´rification ne peut avoir lieu e qu’au moment de l’ex´cution. e De plus, les habitu´s du langage C seront invit´s a se mettre une bonne e e ` fois pour toute dans la tˆte :-) qu’il n’y a pas d’arithm´tique possible sur les e e r´f´rences en Perl. Ajouter 1 a une r´f´rence ne correspond pas a pointer vers ee ` ee ` l’´l´ment d’indice 1 d’un tableau, mais a faire perdre le caract`re r´f´rence ee ` e ee a la variable (elle devient un scalaire comme un autre) : ` my $v my $r print $r++; print = 45; = \$v; "$r\n"; # affiche SCALAR(0x80fd4c4) "$r\n"; # affiche 135255237

On voit bien ici que la variable $r perd son caract`re sp´cifique de e e r´f´rence ; elle a toujours pour valeur l’adresse de la variable (ici incr´ment´e ee e e de 1 : 80fd4c4 est la repr´sentation hexad´cimale du nombre 135255236), e e mais n’est plus une r´f´rence, il sera donc impossible de la d´r´f´rencer. ee eee Notez aussi qu’une r´f´rence peut changer de valeur, c’est-`-dire de vaee a riable point´e et donc de type de variable point´e : e e my $v = 45; my @t = ("ee",-2); my $r = \$v; $$r = -32; # modification de $v $r = \@t; $r->[0] = 28; # modification de $t[0] Derni`re chose importante, si vous passez une r´f´rence a une fonction, e ee ` vous devez bien voir que la copie de la seule r´f´rence est effectu´e, la strucee e ture point´e par la r´f´rence ne l’est pas ; vous pourrez donc la modifier dans e ee la fonction : sub f3 108

c sylvain@lhullier.org

Introduction a la programmation en Perl `

{ my ($reftab) = @_; $reftab->[2] = 32.3; } my @t = ( 49, "hello", -2 ); my $r = \@t; f3( $r ); f3( \@t ); # equivalent ´ # @t est modifi´ e On peut sch´matiser ce qu’il se passe de la mani`re suivante : e e

Visiblité du programme principal $r @t 0 49 1 hello 2 −2 32.3

$reftab

Visibilité de la fonction f3
Les deux r´f´rences pointent donc vers la mˆme zone m´moire. ee e e

11.6

R´f´rences anonymes vers scalaire ee

Une r´f´rence anonyme est une r´f´rence vers une variable qui n’a pas ee ee de nom. Nous avons d´j` vu comment faire cela pour un scalaire avec une ea fonction (fonction f2 un peu avant), mais cela n’est pas la fa¸on de faire la c plus simple. La syntaxe pour cr´er directement une r´f´rence anonyme vers un scae ee laire est la suivante : \valeur-constante my $ref1 = \34; my $ref2 = \"er"; print "$$ref1 $$ref2\n"; 109

Introduction a la programmation en Perl `

c sylvain@lhullier.org

$ref1 34 $ref2 er
Une telle valeur est une constante, il est impossible de modifier la valeur point´e par la r´f´rence (diff´rence avec le m´canisme de la fonction f2) : e ee e e $$ref1 = "hello"; Modification of a read-only value attempted at script.pl line 24. Ce n’est pas dans le cas des scalaires que les r´f´rences anonymes sont ee les plus utilis´es ; elles le sont bien plus avec les tableaux et les tables de e hachage.

11.7

R´f´rences anonymes vers tableau ee

Pour cr´er une r´f´rence anonyme vers un tableau, il faut utiliser la e ee notation suivante : [´l´ment1, ´l´ment2, ´l´ment3, etc] est une r´f´rence ee ee ee ee vers un tableau comportant les ´l´ments en question. ee my $r = [ 34.4, "ac", -71 ]; my @t = ( 34.4, "ac", -71 ); La variable $r est une r´f´rence vers un tableau comportant trois ´l´ments ee ee alors que la variable @t est un tableau a trois ´l´ments (cette derni`re nota` ee e tion nous est d´j` famili`re) : ea e

$r 0 34.4 1 ac 2 −71

@t 0 34.4

1

ac

2

−71

110

c sylvain@lhullier.org

Introduction a la programmation en Perl `

On acc`de aux ´l´ments de cette r´f´rence anonyme comme pour une e ee ee r´f´rence normale : ee print "$r->[0]\n"; $r->[2] = 901; foreach my $e (@$r) { ... } Attention a ne pas ´crire \(2,"er",$v) si vous voulez cr´er une r´f´rence ` e e ee vers un tableau, car cette syntaxe fait toute autre chose : elle est en fait ´quivalente a (\2,\"er",\$v), donc a une liste de r´f´rences, ce qui est fort e ` ` ee diff´rent. e Le structure pr´c´demment d´crite par e e e my @t1 = ( 16, -33 ); my @t2 = ( "el", 0.3, 4 ); my @t = ( 6, \@t1, \@t2, "s" ); peut donc s’´crire de la mani`re suivante : e e my @t = ( 6, [ 16, -33 ], [ "el", 0.3, 4 ], "s" ); Ce qui peut se repr´senter toujours sous la forme suivante : e

@t 0 6 1 2 3 s

0

el

1

0.3

2

4

0

16

1

−33

On peut pousser le vice jusqu’` utiliser une r´f´rence pour le premier a ee tableau : my $r = [ 6, [ 16, -33 ], [ "el", 0.3, 4 ], "s" ]; 111

Introduction a la programmation en Perl `

c sylvain@lhullier.org

$r

0

6

1

2

3

s

0

el

1

0.3

2

4

0

16

1

−33

Comment acc´der aux ´l´ments des diff´rentes profondeurs d’une telle e ee e construction? Il suffit de suivre les r´f´rences ... ee print "$r->[0]\n"; # affiche 6 # $r->[1] est une r´f´rence vers tableau e e print "$r->[1]->[0]\n"; # affiche 16 print "$r->[1]->[1]\n"; # affiche -33 # $r->[2] est une r´f´rence vers tableau e e print "$r->[2]->[0]\n"; # affiche el print "$r->[2]->[1]\n"; # affiche 0.3 print "$r->[2]->[2]\n"; # affiche 4 print "$r->[3]\n"; # affiche s Ce n’est pas si complexe qu’il n’y paraˆ pour peu que nous ayons un bon ıt sch´ma sous la main ... Vous noterez que nous faisons usage de l’op´rateur e e fl`che (->) plutˆt que de la syntaxe double-dollar ($$). e o De plus, si $r->[1] est une r´f´rence vers tableau, @{$r->[1]} est le ee tableau en question. On peut donc ´crire : e foreach my $e ( @{$r->[1]} ) { ... } # Parcourt 16 et -33

Il faut noter qu’en cas de d´r´f´rencements successifs, seule la premi`re eee e fl`che est n´cessaire : $r->[2][1] est ´quivalent a $r->[2]->[1]. e e e ` 112

c sylvain@lhullier.org

Introduction a la programmation en Perl `

11.8

R´f´rences anonymes vers table de hachage ee

De la mˆme fa¸on il est possible de cr´er une r´f´rence anonyme vers une e c e ee table de hachage. La notation {clef1=>valeur1, clef2=>valeur2, etc} est une r´f´rence vers une table de hachage comportant les couples clef/valeur en ee question. my $r = { ’Paul’ ’Julie’ my %h = ( ’Paul’ ’Julie’ => => => => 21, "e" }; 21, "e" );

La variable $r est une r´f´rence vers une table de hachage alors que la ee variable %h est une table de hachage (notation famili`re) : e

$r Julie Paul => => e 21

%h Julie Paul => => e 21

De la mˆme fa¸on qu’avec des tableaux, nous allons mettre sur pied des e c tables de hachage de tables de hachage : my %h1 = ( ’rue’ ’tel’ my %h2 = ( ’rue’ ’tel’ my $r = { ’Paul’ ’Julie’ => => => => => => ’Pasteur’, ’06461341’ ); ’Jaures’, ’03729103’ ); \%h1, \%h2 }; 113

Introduction a la programmation en Perl ` Ou plus directement : my $r = { ’Paul’ => { ’rue’ ’tel’ ’Julie’ => { ’rue’ ’tel’ };

c sylvain@lhullier.org

=> ’Pasteur’, => ’06461341’ }, => ’Jaures’, => ’03729103’ }

$r

Julie Paul

=> =>

rue tel

=>

Jaures

=> 03729103

tel rue

=> 06461341 => Pasteur

Voici comment acc´der a tous les ´l´ments d’une telle construction : e ` ee # $r->{Paul} est une r´f´rence vers une table de hachage e e print "$r->{Paul}->{tel}\n"; # affiche 06461341 print "$r->{Paul}{tel}\n"; # equivalent ´ 114

c sylvain@lhullier.org

Introduction a la programmation en Perl `

print "$r->{Paul}{rue}\n"; # affiche Pasteur # $r->{Julie} est une r´f´rence vers une table de hachage e e print "$r->{Julie}{tel}\n"; # affiche 03729103 print "$r->{Julie}{rue}\n"; # affiche Jaures

Il suffit de suivre sur le sch´ma, d’o` l’importance de faire un bon sch´ma. e u e

11.9

R´f´rences anonymes diverses ee

Il est bient-sˆ r tout a fait possible de m´langer les r´f´rences vers les u ` e ee tableaux et vers les tables de hachage :

my $r = [ [’a’,4], ’b’, [1,’z’], {’P’=>[-2,"er",0],’A’=>7}, 8 ]; 115

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Voici le sch´ma correspondant a cette structure (essayer de vous en e ` convaincre !) :

$r

0

1

b

2

3

4

8

0

1

1

z

0

a

1

4

A P

=> =>

7

0

−2

1

er

2

0

Voici comment acc´der a un ´l´ment d’une telle structure : e ` ee print "$r->[3]->{P}->[1]\n"; # affiche "er" print "$r->[3]{P}[1]\n"; # equivalent ´ Les crochets correspondent a une prise d’indice d’un tableau ; les acco` lades a la clef d’une table de hachage. ` Je peux parcourir le premier tableau du deuxi`me niveau (celui qui come porte a et 4) de la mani`re suivante : e my $reft = $r->[0]; foreach my $v (@$reft) { print "$v\n; } 116

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Je cr´e une variable $reft qui est une r´f´rence vers ce tableau, je peux e ee ensuite parcourir @$reft qui repr´sente le tableau en question. e Il est possible d’´crire cela sans cr´er de variable temporaire, la syntaxe e e est la suivante : @{r´f´rence} Ces accolades n’ont rien a voir avec les tables ee ` de hachage elles permettent juste de d´limiter la r´f´rence a laquelle on e ee ` applique l’arobase. Voici ce que cela donne : foreach my $v (@{$r->[0]}) { print "$v\n"; } On fait de la mˆme fa¸on pour un table de hachage, les accolades d´limitent e c e la r´f´rence a laquelle on applique le pourcentage : ee ` foreach my $k (keys %{$r->[3]}) { print "$k $r->[3]{$k}\n"; } Commencez-vous a voir l’int´ret de faire des sch´mas? ` e e

11.10

L’op´rateur ref e

La question qui pourrait maintenant venir a l’esprit est la suivante : ` comment pourrait-on ´crire une boucle sur les ´l´ments du tableau r´f´renc´ e ee ee e par $r et surtout comment savoir de quel type ils sont pour pouvoir les utiliser? Pour r´pondre a cette question, voici un nouvel op´rateur : ref(). e ` e Il permet de connaˆ le type d’une r´f´rence. ıtre ee Cette fonction renvoie : • • • • "SCALAR" si son argument est une r´f´rence sur scalaire, ee "ARRAY" si son argument est une r´f´rence sur tableau, ee "HASH" si son argument est une r´f´rence sur table de hachage, ee faux si son argument n’est pas une r´f´rence (c’est un scalaire clasee sique).

On peut alors ´crire le code suivant : e foreach my $p (@$r) { 117

Introduction a la programmation en Perl ` if( ref($p) eq "ARRAY" ) { print "( "; foreach my $v (@$p) { print "$v "; } print ")\n"; } elsif( ref($p) eq "HASH" ) { foreach my $k (keys(%$p)) { print "$k : $p->{$k}\n"; } } elsif( !ref($p) ) { print "$p\n"; } } L’affichage suivant est effectu´ : e ( b ( P A 8 a 4 ) 1 z ) : ARRAY(0x8100c20) : 7

c sylvain@lhullier.org

Dans cet exemple, un seul premier niveau de r´f´rences est explor´. Pour ee e aller au-del`, c’est-`-dire, afficher le tableau associ´ a la clef P, il faudrait a a e ` concevoir un ensemble de fonctions s’appelant les unes les autres en fonction du type des r´f´rences rencontr´es. Ne vous fatiguez pas a les ´crire, il existe ee e ` e d´j` une telle fonctionnalit´ en Perl : ea e use Data::Dumper; print Dumper($r); La premi`re ligne ajoute des fonctions a Perl (c’est un peu le #include du e ` langage C) et ne doit donc ˆtre pr´sente qu’une seule fois dans le programme e e (plutˆt au d´but). La seconde consiste en l’affichage de la valeur de retour de o e la fonction Dumper : cette fonction renvoie une (longue) chaˆ de caract`res ıne e repr´sentant toute la structure r´f´renc´e par $r : e ee e $VAR1 = [ 118

c sylvain@lhullier.org

Introduction a la programmation en Perl `

[ ’a’, 4 ], ’b’, [ 1, ’z’ ], { ’P’ => [ -2, ’er’, 0 ], ’A’ => 7 }, 8 ];

Vous noterez que l’affichage effectu´ est directement int´grable dans un e e code Perl.

11.11

R´f´rences circulaires ee

La notion de r´f´rence circulaire n’a rien de compliqu´ ; c’est juste le fait ee e que plusieurs tableaux et/ou tables de hachage et/ou scalaires peuvent se 119

Introduction a la programmation en Perl ` r´f´rencer entre elles. Par exemple : ee

c sylvain@lhullier.org

$r

0

71

1

* Od R5 => => As4 Hello Ptt => => −34.7

On voit bien alors qu’un cycle de r´f´rences existe entre ces r´f´rences. ee ee Voici comment ´crire cela en Perl : e my $r = [ 71, { "Hello" => -34.7, "Ptt" => { "R5" => "As4" } } ]; $r->[1]{Ptt}{Od} = $r; On comprend bien qu’il n’est pas possible de cr´er une telle structure en e une seule instruction. Comment se comporte Data::Dumper dans une telle situation? Ne va-t-il pas boucler a l’infini? Et bien non : il se comporte bien : ` print Dumper($r); $VAR1 = [ 71, 120

c sylvain@lhullier.org

Introduction a la programmation en Perl `

{ ’Ptt’ => { ’R5’ => ’As4’, ’Od’ => $VAR1 }, ’Hello’ => ’-34.7’ } ]; Data::Dumper se rend compte qu’il passe sur une r´f´rence qu’il a d´j` ee ea parcourue et l’affiche comme telle ($VAR1). Pourquoi vous parler de r´f´rences circulaires? Premi`rement parce qu’il ee e faut savoir qu’il est possible d’en faire (cela peut ˆtre utile de cr´er des listes e e chaˆ ees circulaires etc). Mais surtout parce qu’elles posent des probl`mes ın´ e ` la suite a au garbage-collector dans sa tˆche de lib´ration de la m´moire. A a e e ` l’exemple pr´c´dent, je pourrais ´crire : e e e $r = undef; En temps normal, tout ce que $r r´f´ren¸ait serait lib´r´. Mais ici, ce ee c ee n’est pas le cas. En effet, chacun des tableaux et des tables de hachage ont encore au moins une r´f´rence vers elle, le garbage-collector ne se rend ee pas compte, qu’en fait, les trois objets peuvent ˆtre lib´r´s. Nous sommes e ee donc en pr´sence de zones m´moires inaccessibles (aucune variable ne nous e e permet d’y acc´der) et non lib´rables : cette m´moire est perdue pour le e e e programme ! Elle sera bien sˆ r lib´r´e quand le programme prendra fin, u ee mais s’il s’agit d’un d´mon qui tourne en permanence, cette fuite m´moire e e n’est pas forc´ment a n´gliger. e ` e La solution pour ´viter cela est de ”casser” la circularit´ avant de modie e fier la valeur de la variable $r : $r->[1] = undef; Je viens de casser le lien indiqu´ par un ast´risque, il n’y a plus de boucle e e dans les r´f´rences. Maintenant et seulement maintenant, je puis sans risque ee ´crire : e $r = undef; Et la m´moire sera lib´r´e ... e ee 121

Introduction a la programmation en Perl `

c sylvain@lhullier.org

11.12

R´f´rences sur fichiers ee

Une ouverture de fichier cr´e une variable dont il est possible de prendre e l’adresse. Voici la syntaxe pour cela : open(FILE,">toto") or die("$!"); my $reff = \*FILE; La variable scalaire $reff est une r´f´rence vers le descripteur de fichier ee FILE. Il nous est aussi possible de cr´er une r´f´rence vers un des trois fichiers e ee pr´-existant : e my $refo = \*STDOUT; Voici des exemples d’utilisation de ces r´f´rences : ee open(FILE,">toto") or die("$!"); my $reff = \*FILE; print $reff "ok\n"; sub affiche { my ($ref) = @_; print $ref "ok\n"; } affiche( $reff ); affiche( \*FILE ); # equivalent ´ close( $reff ); Cette derni`re ligne est ´quivalente a close(FILE); On peut sans rese e ` trictions stocker une r´f´rence vers fichier dans une table de hachage ou dans ee un tableau.

11.13

R´f´rences sur fonctions ee

Comme dans le langage C, une fonction a elle-aussi une adresse m´moire. e Cette adresse correspond a l’endroit de la m´moire o` le code de la fonction ` e u est stock´. On peut obtenir une r´f´rence vers une fonction de la mani`re e ee e suivante : sub affcoucou { my ($p) = @_; 122

c sylvain@lhullier.org

Introduction a la programmation en Perl `

print "Coucou $p\n"; } my $ref = \&affcoucou; La variable scalaire $ref est une r´f´rence vers la fonction affcoucou. ee Elle peut s’utiliser des fa¸ons suivantes : c &$ref("Larry"); # appel $ref->("Larry"); # equivalent ´ sub f { my ($f,$p) = @_; $f->( $p ); } f( $ref, "Larry" ); f( \&affcoucou, "Larry" ); # equivalent ´ Notez bien qu’il est tout a fait possible de stocker une telle r´f´rence ` ee dans un tableau ou dans une table de hachage ...

11.14

Un dernier mot sur les r´f´rences ee

De telles structures nous donnent envie de faire de la programmation objet (champs et m´thodes pourraient ˆtre stock´es dans une table de hae e e chage). N’allons pas trop vite car Perl a ´t´ pr´vu pour la programmation ee e objet et propose les fonctionnalit´s n´cessaires (h´ritage ...) en se basant sur e e e les modules.

123

Introduction a la programmation en Perl `

c sylvain@lhullier.org

124

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 12

Utilisation de modules
Nous allons aborder ici l’usage des modules, c’est-`-dire de biblioth`ques a e ou encore librairies. Perl tire sa puissance de la richesse des modules existants ; peu d’autres langages (voire aucun) ne peuvent pr´tendre ˆtre aussi e e riche que Perl. Par exemple, quasiment tous les protocoles r´seau auxquels e vous pouvez penser sont accessibles en Perl en utilisant un module existant. En quelques mots, un module est un ensemble de fonctions regroup´es e dans un fichier. Ces fonctions y sont regroup´es car elles touchent toutes e a un mˆme domaine, a un mˆme ensemble de fonctionnalit´s autour d’une ` e ` e e mˆme utilisation, d’un mˆme protocole ... e e La premi`re chose que je vous invite a faire, c’est a lancer la commande e ` ` perl -V : elle affiche toute sorte d’informations, dont le contenu de la variable @INC. Cette variable de type tableau contient la liste des r´pertoires e o` seront recherch´s les modules. Le nom INC rappelle ´trangement (et c’est u e e voulu) la notion d’include en C. L’ordre des r´pertoires de cette variable est e important car si un module vient a ˆtre pr´sent dans deux r´pertoires, seule `e e e l’occurrence pr´sente dans le premier r´pertoire de la liste comptera (mais e e ce cas proviendrait plutˆt d’une erreur de nommage ou d’installation). o

12.1

Utilisation d’un premier module

Il existe de nombreux modules d´j` install´s sur votre syst`me ; une ea e e distribution de Perl inclut les modules les plus utilis´s. e Ainsi, le module nomm´ Math::Trig ; permet d’acc´der a des fonce e ` tions math´matiques de trigonom´trie autres que les seuls cosinus et sinus e e pr´d´finis dans Perl sous les noms de cos et sin. e e Je vous invite a taper la commande perldoc Math::Trig dans un termi` 125

Introduction a la programmation en Perl `

c sylvain@lhullier.org

nal ; vous visualiserez ainsi la documentation de ce module. Cette commande perldoc fonctionne un peu comme la commande man ; vous verrez d´taill´es e e les fonctionnalit´s auxquelles vous avez acc`s avec un module donn´. Vous e e e taperez ’q’ pour quitter. On voit ici que nous avons acc`s a des fonctions comme tan, acos ou e ` asin ainsi qu’` des fonctions de conversion entre unit´s d’angles ou bien a e a la valeur de pi. De petits exemples simples d’utilisations vous sont aussi ` fournis. La premi`re ligne de code a ´crire pour utiliser un module est la suivante : e `e use NomDuModule; Dans bien des cas, cette instruction ajoute des fonctions et des variables a l’espace de nommage (nous reviendrons sur ce point dans la suite). Pour ` notre exemple, la ligne est : use Math::Trig; Cette ligne devra ˆtre plac´e dans chaque script qui fait usage du module e e et ˆtre ex´cut´e avant tout usage de fonctions ou de variables du module. e e e Typiquement toutes les lignes use sont regroup´es au d´but du script. e e Vous remarquerez que la ligne use strict; que je vous ai conseill´ de e placer dans chaque script, n’est en fait que le chargement d’un module ; ce module ayant pour rˆle de rendre la syntaxe Perl plus coercitive. Le nom des o modules de ce type est en minuscule. Ils sont appel´s modules pragmatiques. e Ils ont pour objet de modifier ou d’´tendre la s´mantique de Perl. Ainsi e e diagnostics permet d’avoir des messages d’erreurs plus complets (vous pouvez charger sur CPAN la version 1.2-alpha1 qui vous permet d’avoir ces messages avec des explications en fran¸ais). c Revenons a notre module Math::Trig. Voici un exemple de code Perl ` l’utilisant (j’en plagie ici la documentation) : use Math::Trig; $x = tan(0.9); $y = acos(3.7); $z = asin(2.4); $pi_sur_deux = pi/2; $rad = deg2rad(120); Je laisse au lecteur le soin de deviner (ou plutˆt comprendre) ce que font o ces instructions. Une fois charg´, un module n’est pas ”d´chargeable”. e e 126

c sylvain@lhullier.org

Introduction a la programmation en Perl `

12.2

D’autres modules

Voici l’exemple d’un autre module : File::Copy ; il permet certaines manipulations de fichiers lourdes a mettre en œuvre avec de simples ap` pels syst`me. Il est par exemple possible de copier un fichier vers un autre e (fichiers disque ou flux de donn´es), ou d’en d´placer un d’une partition e e vers une autre (impossible avec l’appel syst`me rename). Comme l’indique e perldoc File::Copy : use File::Copy; copy("file1","file2"); copy("Copy.pm",\*STDOUT);’ move("/dev1/fileA","/dev2/fileB"); Voici un autre exemple de module en action. Il s’agit du module Net:FTP qui nous permet d’acc´der tr`s simplement aux fonctionnalit´s d’un client e e e FTP. Voici, par exemple, comment se connecter sur un serveur (en mode passif, car j’ai un firewall), changer de r´pertoire et t´l´charger un fichier : e ee #!/usr/bin/perl -w use strict; use Net::FTP; my $ftp = Net::FTP->new("ftp.cpan.org", Debug => 0, Passive =>1 ) or die("$!"); $ftp->login("anonymous",’-anonymous@’); $ftp->cwd("/pub/CPAN/"); $ftp->get("ls-lR.gz"); $ftp->quit(); On remarquera au passage la notation objet (new, ->) ; beaucoup de modules l’utilisent. Mˆme si nous ne verrons la programmation objet que e dans une prochaine partie, il est ais´ de comprendre comment utiliser de e tels modules (de toute fa¸on la documentation des modules comporte des c exemples). Quoi de plus simple finalement pour faire du FTP client ? Comment faisais-je avant pour mettre a jour mon site web des seules pages que j’ai ` modifi´es depuis la derni`re fois??? e e

12.3

O` trouver les modules ? u

C’est tr`s bien tout cela, mais comment trouver le module qui r´pond e e a mon probl`me? Pour cela je dois vous pr´senter l’archive de tous les mo` e e 127

Introduction a la programmation en Perl `

c sylvain@lhullier.org

dules Perl, j’ai nomm´ CPAN (Comprehensive Perl Archive Network). Cette e archive recense tous les modules diffus´s pour Perl. e Je vous invite a visiter le site http://www.cpan.org/ vous y trouverez de ` tout a propos de Perl. Vous pouvez t´l´charger les sources de l’interpr´teur ` ee e (Perl source code), des versions compil´es (Perl binary distributions) dispoe nibles pour de tr`s nombreuses plate-formes, ainsi que de la documentation e sur les modules et de quoi les t´l´charger. Le lien int´ressant est : CPAN moee e dules, distributions, and authors (search.cpan.org). Une page vous est propos´e avec de nombreuses sections listant des modules regroup´s par th`me, e e e ainsi qu’un champ de saisie servant a la recherche de mots clefs dans les ` modules. Je vous invite a entrer SMTP et a voir la vari´t´ des modules qui ` ` ee gravitent autour de ce protocole ; le module le plus int´ressant est sˆ rement e u Net::SMTP (plus le nom d’un module est court et semble canonique, plus il y a de chance qu’il soit int´ressant). Diff´rents liens permettent de visualie e ser la documentation (le perldoc correspondant) ainsi que de t´l´charger le ee module le cas ´ch´ant. e e L’installation de modules CPAN n’est pas au menu de ce document, je ne vais pas m’appesantir sur la question ; juste deux mots pour vous dire que les commandes perl Makefile.PL, make, make test et make install sont la clef du succ`s. Les modules CPAN sont pr´sents sous forme de package e e dans toute bonne distribution Linux. Par exemple sous Debian, il s’agit des paquets libxxx-yyy-perl (o` xxx-yyy correspond au nom du module u Xxx::Yyy mis en minuscules). Mˆme si vous n’installez pas de module, CPAN n’en reste pas moins e la source majeure d’informations sur les modules de votre syst`me. Vous e vous rendez par exemple compte que le module Net::SMTP r´pond a vos e ` besoins, vous v´rifiez alors que ce module est pr´sent sur votre syst`me en e e e tapant perl -e ’use Net::SMTP’ et vous n’avez plus qu’` l’utiliser. La a documentation sera accessible par perldoc Net::SMTP Juste pour sourire deux minutes, je vous invite a rechercher dans CPAN ` un module nomm´ Sex ´crit un premier avril et d’en lire la documentation e e (ainsi que le code) ...

128

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 13

´ Ecrire un module
Apr`s avoir manipul´ des modules existants et avoir parl´ de CPAN, e e e nous allons maintenant apprendre a ´crire nos propres modules. `e

13.1

Premier exemple

Pour ´crire un module, nous devons cr´er un fichier ind´pendant du ou e e e des scripts qui l’utilisent. L’extension de ce fichier est imp´rativement .pm : e par exemple Utils.pm Ce fichier doit ˆtre plac´ dans un des r´pertoires e e e list´s dans la variable @INC ; pour commencer vous pourriez le placer dans e votre r´pertoire de travail a cˆt´ du script qui l’utilisera, car le r´pertoire . e ` oe e est pr´sent dans ce tableau @INC. e Ce fichier doit contenir une premi`re ligne indiquant le nom du module ; e pour cela, vous devez ´crire : e package Utils; Il est important de voir que le nom du package doit ˆtre le mˆme que celui e e du fichier (` l’extension pr`s). Le fichier peut ensuite contenir des d´finitions a e e de fonctions. Voici un exemple simple d’un tout petit module complet : # --- fichier Utils.pm --package Utils; use strict; sub bonjour { my ($prenom) = @_; print "Bonjour $prenom\n"; 129

Introduction a la programmation en Perl ` } 1;

c sylvain@lhullier.org

Il est important de ne pas oublier la derni`re ligne, celle qui contient 1; ; e nous reviendrons plus tard sur son rˆle. o Pour pouvoir utiliser ce module dans un script, il est n´cessaire d’ine voquer l’instruction use suivie du nom du module. Voici un exemple de l’utilisation du module pr´c´dent : e e #!/usr/bin/perl -w # --- fichier script.pl --use strict; use Utils; # chargement du module Utils::bonjour( "Paul" ); La derni`re ligne correspond a l’appel de la fonction bonjour du module e ` Utils. La syntaxe est la suivante : le nom du module est suivi de deux signes deux-points puis du nom de la fonction.

13.2

Et les variables ?

Il est possible de d´clarer des variables propres au module. Ces variables e seront : • soit accessibles exclusivement aux fonctions pr´sentes dans le module e (on pourrait parler de variables priv´es, correspondant aux variables e static d´clar´es en dehors des fonctions en C), e e • soit aussi accessibles a l’ext´rieur du module (on pourrait parler de ` e variables publiques ou variables globales). Une variable accessible exclusivement aux fonctions du module se d´clare e avec my (que l’on connaˆ d´j`). Une variable aussi accessible depuis l’ext´rieur ıt e a e du module se d´clare avec our (my pour dire ”` moi”, our pour dire ”` e a a nous”). Avant la version 5.6 de Perl, on utilisait un autre m´canisme dont e je ne parlerai pas ici, assurez-vous d’avoir une version r´cente de Perl (cf e perl -v). Ces variables doivent ˆtre d´clar´es en dehors de toute fonction ; e e e les variables d´clar´es dans les fonctions sont comme toujours locales au bloc e e dans lequel elles sont d´clar´es. e e # --- fichier Utils.pm --package Utils; 130

c sylvain@lhullier.org

Introduction a la programmation en Perl `

use strict; # variable accessible our $x = ’toto’; # variable inaccessible my $y = ’toto’; # fonction sub bonjour { # Variable locale my ($prenom) = @_; print "Bonjour $prenom\n"; print "$x $y\n"; } 1; Que la variable soit d´clar´e avec my ou avec our, il est tout a fait possible e e ` ` l’inverse, depuis d’y acc´der depuis une fonction du module (ici bonjour). A e l’ext´rieur du module, c’est-`-dire depuis le script, seule la variable $x est e a accessible. #!/usr/bin/perl -w # --- fichier script.pl --use strict; use Utils; Utils::bonjour( "Paul" ); # Ok : print "$Utils::x\n"; # Erreur : print "$Utils::y\n"; De mˆme que pour les fonctions, les noms de variable sont pr´fix´s par e e e le nom du module puis deux signes deux-points. Ici, le nom complet de la variable est donc Utils::x qu’il faut faire pr´c´der d’un signe dollar, ce qui e e donne : $Utils::x au final. Il n’y a pas d’erreur de ma part : on n’´crit pas e Utils::$x ! :-)

13.3

De la derni`re ligne d’un module e

Jusqu’ici, nous avons toujours plac´ une ligne 1; a la fin du fichier de e ` notre module. Il faut savoir que cette valeur est la valeur du chargement du 131

Introduction a la programmation en Perl `

c sylvain@lhullier.org

module (valeur de l’instruction use Utils;) et qu’elle indique si ce chargement s’est bien pass´ ou non : une valeur fausse indique un probl`me, une e e valeur vraie (comme ici 1) indique au contraire que le chargement s’est bien d´roul´. Une valeur fausse mettra fin au script qui fait appel a l’instruction e e ` use. Il est donc tout a fait possible de mettre une autre valeur qu’une valeur ` constante ; on peut, par exemple, envisager mettre un test en derni`re inse truction pour v´rifier si les conditions sont r´unies pour l’usage du module. e e On pourrait imaginer conditionner le chargement du module a l’ouverture ` d’un fichier, d’une connexion r´seau (ou je-ne-sais-quoi encore...). Je ne done nerai pas d’exemple ici car le cas est rare de la n´cessit´ d’un tel usage, mais e e il faut savoir que cela est possible.

13.4

R´pertoires e

Voyons maintenant comment cr´er des modules aux noms compos´s e e comme Truc::Utils (nous avons par exemple vu le module Net::FTP). Ces noms compos´s permettent de regrouper les modules par type d’usages ; par e exemple Net correspond a tout ce qui concerne le r´seau. ` e Revenons a notre exemple Truc::Utils. Ce nom Truc correspond a un ` ` r´pertoire qui doit ˆtre pr´sent dans un des r´pertoires de la variable @INC e e e e (par exemple .) et le fichier Utils.pm doit ˆtre pr´sent dans ce r´pertoire e e e Truc. Voici un exemple de tel module : # --- fichier Truc/Utils.pm --package Truc::Utils; use strict; our $x = ’toto’; sub bonjour { my ($prenom) = @_; print "Bonjour $prenom\n"; } 1; Et voici un script l’utilisant : #!/usr/bin/perl -w # --- fichier script.pl --132

c sylvain@lhullier.org

Introduction a la programmation en Perl `

use strict; use Truc::Utils; Truc::Utils::bonjour( "Paul" ); print "$Truc::Utils::x\n"; Rien de sorcier.

13.5

Blocs BEGIN et END

Les amoureux de awk retrouveront ici deux de leurs enfants pr´f´r´s eee :-)). Dans un module, il est possible de pr´voir deux blocs d’instructions e qui seront ex´cut´s soit d`s le chargement du module (bloc BEGIN) soit lors e e e de la fin de l’usage du module (bloc END). package Utils; use strict; sub f { .... } BEGIN { print "Chargement du module\n"; } END { print "Fin d’usage du module\n"; } 1; Notez bien qu’il ne s’agit pas de fonctions (pas de mot clef sub), mais bien de blocs lab´lis´s. Le bloc BEGIN sera ex´cut´ lors de l’instruction e e e e use Utils; avant toute autre instruction du module (y compris les use plac´s dans le module). Le bloc END sera ex´cut´ lors de la fin du programme. e e e L’usage de ces deux blocs peut ˆtre n´cessaire lorsque l’utilisation du e e module est conditionn´e par l’obtention d’une ou plusieurs ressources comme e un fichier ou une connexion r´seau. Ces blocs vont nous servir a pr´parer le e ` e terrain au d´but et a lib´rer les ressources a la fin. e ` e ` Lorsque dans un module sont pr´sentes d’autres instructions que des e d´finitions de variables et des d´finitions de fonctions, ces instructions sont e e ex´cut´es au moment du chargement du module. Tout se passe comme si e e ces instructions figurent dans un BEGIN implicite. L’usage d’un bloc BEGIN permet juste au programmeur d’´crire un code un peu plus lisible et e 133

Introduction a la programmation en Perl `

c sylvain@lhullier.org

propre, dans la mesure o` toutes ces instructions sont regroup´es sous un u e nom (BEGIN) qui rappelle explicitement qu’elles sont ex´cut´es au d´but. e e e Notez bien que la programmation objet (lire la suite) a quelque peu rendu ces deux blocs obsol`tes voire inutiles. e

13.6

Introduction ` l’export de symboles a

Sous ce titre barbare se cache une id´e simple : il peut ˆtre p´nible de e e e toujours ´crire le nom complet des fonctions de modules. Je veux dire par e l` que d’´crire Utils::bonjour a chaque fois que vous voulez appeler cette a e ` fonction est sans doute lourd et est quelque peu p´nible a la longue. Il existe e ` un moyen pour n’avoir qu’a ´crire bonjour sans avoir a rappeler le nom e ` du module qui contient la fonction. En faisant cela nous allons ajouter la fonction dans l’espace de nommage du script. Placer une fonction ou une variable d’un module dans l’espace de nommage d’un script ou d’un autre module s’appelle faire un export, on parle d’exporter le symbole (fonction ou variable). Ce symbole est donc import´ e par le script. Pour avoir la capacit´ d’exporter des symboles, notre module future exportateur doit comporter les lignes suivantes : package Utils; use Exporter; our @ISA = qw(Exporter); Ces deux nouvelles lignes d’instructions doivent ˆtre plac´es juste apr`s e e e l’instruction package. La premi`re est l’invocation du module Exporter ; e avec la seconde on indique que notre module est un (ISA) Exporter (nous reverrons cette syntaxe et ses implications en programmation objet). Notre module est maintenant capable d’exporter des symboles. Il existe quatre types de symboles (fonctions ou variables) : • ceux qui sont export´s pas d´faut : le script utilisant le module n’a e e rien besoin de faire de sp´cial (autre que de faire le use) pour que ces e symboles soient export´s, e • ceux qui sont individuellement exportables en fonction de ce que demande le script utilisateur, • ceux qui sont exportables en groupe (on parle de tags) selon ce que demande le script utilisateur, 134

c sylvain@lhullier.org

Introduction a la programmation en Perl `

• ceux qui ne sont pas exportables (c’est-`-dire qu’il faudra toujours a faire pr´c´der leur nom par le nom complet du module). e e Chacun des trois premiers ensembles est associ´ a une variable d´clar´e e` e e avec our.

13.7

Export par d´faut de symboles e

Les symboles export´s par d´faut doivent ˆtre list´s dans la variable e e e e @EXPORT ; il s’agit donc d’un tableau. Il est courant d’initialiser ce tableau avec l’op´rateur qw que nous avons d´j` vu et sur lequel je ne reviendrai e ea donc pas : our @EXPORT = qw(&bonjour &hello $var); Cette ligne plac´e dans le module Utils a la suite de la ligne e ` our @ISA = qw(Exporter); va permettre d’utiliser les fonctions bonjour et hello ainsi que la variable scalaire $var sans pr´fixe dans le script utilisateur. Notez bien que, si e les variables doivent ˆtre cit´es avec leur caract`re de diff´rentiation de type e e e e (le dollar, l’arobase ou le pourcentage), il en est de mˆme avec les fonctions e et le signe ”et-commercial” (&). Sachez juste que ce et-commercial peut ˆtre e omis. Voici comment on peut maintenant utiliser le module en question : use Utils; bonjour("Paul"); hello("Peter"); print "$var\n"; Plutˆt simple. o

13.8

Export individuel de symboles

Un symbole peut ˆtre export´ a la demande de celui qui utilise le module. e e` C’est-`-dire que ce symbole n’est pas export´ par d´faut, mais il peut faire a e e l’objet d’un export s’il est nomm´ment cit´ lors de l’instruction use. e e Un symbole doit apparaˆ dans la variable @EXPORT_OK pour ˆtre auıtre e toris´ a ˆtre export´ : e`e e our @EXPORT_OK = qw(&gutenTag &ciao $var2); 135

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Ces trois symboles sont maintenant exportables dans le script utilisant ce module. Pour cela il convient d’ajouter une liste de symboles a l’instruction ` use : use Utils qw(&ciao $var2); ciao("Paula"); print "$var2\n"; Cette ligne importe donc les symboles demand´s et ces derniers sont e donc utilisables sans pr´fixe. e Il se trouve qu’une telle ligne n’importe plus les symboles par d´faut e (ceux de la variable @EXPORT) ; ne me demandez pas pourquoi, je trouve cela aussi stupide que vous ... Pour rem´dier a cela, il nous faut ajouter a la liste e ` ` des imports le tag :DEFAULT : use Utils qw(:DEFAULT &ciao $var2); bonjour("Paul"); hello("Peter"); print "$var\n"; ciao("Paula"); print "$var2\n"; Ce m´canisme de s´lection des symboles export´s permet a l’utilisateur e e e ` du module de ne pas trop polluer son espace de nommage et de choisir les seules fonctions dont il aura besoin.

13.9

Export par tags de symboles

Il est possible de regrouper les symboles dans des tags. Un tag est une liste de symboles. L’import d’un tag provoque l’import de tous les symboles composant ce tag. La variable qui entre ici en jeu est %EXPORT_TAGS ; il s’agit ` donc d’une table de hachage. A chaque tag est associ´e une r´f´rence vers e ee un tableau contenant la liste des symboles du tag : our %EXPORT_TAGS=(T1=>[qw(&ciao &gutenTag)], T2=>[qw(&ciao $var2)]); Le tag T1 est associ´ aux fonctions ciao et gutenTag. Le tag T2 est e associ´ a la fonction ciao et a la variable $var2. Le nom des tags est par e ` ` convention en majuscules. 136

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Remarque importante : les symboles pr´sents dans les listes associ´es e e aux tags doivent absolument ˆtre pr´sents dans @EXPORT et/ou @EXPORT_OK. e e Dans le cas contraire, leur export sera impossible. Voici un usage de ce module : use Utils qw(:T2); ciao("Paula"); print "$var2\n"; Le nom du tag est plac´ dans la liste des modules pr´c´d´ par le signe e e e e deux-points. Il est possible de combiner les diff´rents types d’acc`s : e e use Utils qw(:DEFAULT &ciao :T1); bonjour("Paul"); hello("Peter"); print "$var\n"; ciao("Paula"); print "$var2\n"; gutenTag("Hans"); On voit alors que DEFAULT est un tag.

13.10

Exemple complet d’exports

Voici un exemple complet d’usage des exports dans les modules ; j’ai essay´ de regrouper toutes les configurations. e Voici le module Utils dans le fichier Utils.pm : package Utils; use strict; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(&f1 &f2); our @EXPORT_OK = qw(&f3 &f4 &f5 &f6); our %EXPORT_TAGS = (T1 => [qw(&f5 &f6)], T2 => [qw(&f4 &f6)]); sub f1 { print "f1\n"; } sub f2 { print "f2\n"; } sub f3 { print "f3\n"; } sub f4 { print "f4\n"; } sub f5 { print "f5\n"; } 137

Introduction a la programmation en Perl ` sub f6 { print "f6\n"; } 1;

c sylvain@lhullier.org

Et voici un script l’utilisant (apr`s chaque appel de fonction est signal´e e e la raison qui fait qu’il est possible de l’appeler sans pr´fixe) : e #!/usr/bin/perl -w use strict; use Utils qw(:DEFAULT :T2 &f3); f1(); # tag DEFAULT f2(); # tag DEFAULT f3(); # individuellement f4(); # tag T2 Utils::f5(); # pas import´e e f6(); # tag T2 Notez bien le cas de la fonction f5 qui n’est pas import´e, mais qui n’en e reste pas moins utilisable. Pour plus d’informations et d’exemples je vous invite a vous r´f´rer a ` ee ` perldoc Exporter.

13.11

Fonctions inaccessibles

Vous allez me poser la question suivante : comment faire pour rendre une fonction d’un module inaccessible depuis le script? Et je vous r´pondrai : cela e n’est a priori pas possible (vous allez voir que si finalement). Vous l’avez compris, Perl n’est pas un langage extrˆmement coercitif, e notamment par rapport a des langages comme Java ou C++. Il n’y a donc ` rien de pr´vu dans le langage pour rendre certaines fonctions uniquement e accessibles depuis l’int´rieur du module. Est alors apparue la convention e suivante : toute fonction ou variable dont le nom commence par un soulign´ e (ou under-score ’_’) est priv´e et ne doit pas ˆtre utilis´e a l’ext´rieur du e e e ` e module. Cette confiance en l’utilisateur du module est souvent suffisante et les modules CPAN sont bˆtis sur ce mod`le. a e N´anmoins, si vous ˆtes outr´ par ce que je viens d’´crire car vous ˆtes e e e e e un fanatique de Java ou autres, il existe un moyen d’´crire des fonctions e vraiment internes aux modules. Il faut pour cela d´clarer une variable avec e my (donc invisible depuis l’ext´rieur du module) et d’en faire une r´f´rence e ee anonyme vers fonction : package Utils; 138

c sylvain@lhullier.org

Introduction a la programmation en Perl `

use strict; my $affiche = sub { my ($n,$m) = @_; print "$n, $m\n"; }; La variable $affiche est donc une variable priv´e qui pointe vers une e fonction anonyme. Son usage est donc r´serv´ aux fonctions d´clar´es dans e e e e le module : sub truc { $affiche->(4,5); } Remarquez que, comme le code Perl est toujours accessible en lecture, il est toujours possible a l’utilisateur du module de prendre le code en copier` coller et d’en faire une fonction personnelle ... Perl n’est pas fait pour les parano¨ ıaques.

13.12

Documentation des modules

Documenter son travail est important pour une r´-utilisation du code e par d’autres ou mˆme par soi-mˆme plus tard ... En Perl la documentation e e des modules se fait dans le code mˆme du module. Une syntaxe particuli`re, e e nomm´e POD, permet cela. Les instructions POD commencent toujours par e le signe ´gal (=). e La documentation d’un module commence typiquement ainsi : =head1 NAME Utils.pm - Useful functions =head1 SYNOPSIS use Utils; bonjour("Paul"); =head1 DESCRIPTION

139

Introduction a la programmation en Perl ` Blabla blabla =head2 Exports =over =item :T1 Blabla =item :T2 Blabla =back =cut

c sylvain@lhullier.org

Les tags =head1 d´finissent des en-tˆtes de premier niveau (des gros e e titres) et les tags =head2 d´finissent des en-tˆtes de deuxi`me niveau (des e e e sous-titres). Il est de coutume de mettre les premiers exclusivement en majuscules. Les tags =over, =item et =back permettent de mettre en place une liste. Le reste du texte est libre. Le tag =cut indique la fin du POD. Les blocs de POD et les portions de code peuvent alterner : cela est mˆme e recommand´ de documenter une fonction et d’en faire suivre le code. Pour e cela vous devez savoir que l’apparition en d´but de ligne d’un tag POD ine dique la fin temporaire du code Perl et le d´but d’un bloc de documentation. e La fin de ce POD est signal´e a l’aide du tag =cut et le code Perl peut alors e ` reprendre. package Utils; =head1 FUNCTION hello This function prints hello. =cut sub hello { my ($firstName) = @_; print "Hello $firstName\n"; } =head1 FUNCTION bonjour 140

c sylvain@lhullier.org

Introduction a la programmation en Perl `

This function prints hello in french. =cut sub bonjour { my ($prenom) = @_; print "Bonjour $prenom\n"; } Comment visualiser une telle documentation, allez-vous me demander? Rien de plus simple : perldoc est notre alli´ ! Tapez donc perldoc Utils e (ou tout autre nom que vous aurez choisi de donner a votre module) et ` sa documentation apparaˆ au format man comme tout bon module CPAN. ıt Quoi de plus simple? NAME Utils.pm - Useful functions SYNOPSIS use Utils; bonjour("Paul"); DESCRIPTION Blabla blabla Exports :T1 Blabla :T2 Blabla FUNCTION hello This function prints hello. FUNCTION bonjour This function prints hello in french. Pour plus d’informations et de d´tails sur ce format, je vous invite a e ` consulter perldoc perlpod o` de nombreux exemples sont donn´s. Vous u e pouvez aussi jeter un oeil au code d’un module ou deux dont le perldoc vous intrigue ... 141

Introduction a la programmation en Perl `

c sylvain@lhullier.org

13.13

Un dernier mot sur les modules

J’esp`re que la lecture de cette partie vous a donn´ envie de structurer e e votre code en regroupant vos fonctions dans de telles biblioth`ques. Vous e vous rendrez compte de cette n´cessit´ lorsque vous aurez un fichier de e e code trop gros a g´rer ... Mais mˆme sans cela, n’h´sitez pas a faire des ` e e e ` modules, ne serait-ce que pour une r´-utilisation de fonctionnalit´s dans e e d’autres scripts ou pour partager votre code avec des amis, des coll`gues e voire avec la communaut´. e

142

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Chapitre 14

Programmation objet
La programmation objet est le concept nouveau de ces vingt derni`res e ann´es. C++ est bˆti sur le C et apporte l’objet. Java a ´t´ mis au point e a ee (entre autres) pour passer outre les nombreux pi`ges et probl`mes de C++. e e Ruby est un langage interpr´t´ bas´ sur ce concept objet. ee e Perl, qui utilisait un garbage collector bien avant que Java n’existe, ne pouvait pas ˆtre en reste et la communaut´ Perl a rapidement propos´ les e e e extensions du langage n´cessaires a ce type de programmation. e ` On notera que ces extensions sont peu nombreuses car l’id´e a ´t´ de e ee r´utiliser au maximum ce qui existait d´j` en Perl et de l’appliquer a la e ea ` programmation objet. Le C++ ´tant compil´ et devant rester compatible e e avec le C, cela fut un challenge de mettre sur pied ce langage ; cela explique sans doute pourquoi C++ est si complexe et comporte tant de pi`ges. Perl, e de par sa nature interpr´t´e, n’a pas pos´ de probl`me pour s’´tendre a ee e e e ` l’objet. La programmation par objets ouvre le champ des possibilit´s offertes au e programmeur ; alli´e a un langage puissant et flexible comme Perl, elle offre e ` la souplesse, la richesse et la facilit´ d’´criture qu’il manque aux langages e e uniquement objet. Toutefois, de par sa nature permissive, le langage Perl ne saurait ˆtre aussi strict que des langages exclusivement objet. Le programe meur est invit´ a faire les choses proprement, mais rien de l’y oblige. e`

14.1

Vous avez dit objet ?

Sans revenir sur la th´orie de la programmation objet, je vais tenter ici e d’y faire une courte introduction. La programmation orient´e objet est un e type de programmation qui se concentre principalement sur les donn´es. La e 143

Introduction a la programmation en Perl `

c sylvain@lhullier.org

question qui se pose en programmation OO (orient´e objet) est ”quelles sont e les donn´es du probl`me?” a l’instar de la programmation proc´durale par e e ` e exemple, qui pose la question ”quelles sont les fonctions/actions a faire ?”. ` En programmation OO, on parle ainsi d’objets, auxquels on peut affecter des variables/attributs (propri´t´s) et des fonctions/actions (m´thodes). ee e On parle de ”classe”, qui est une mani`re de repr´senter des donn´es e e e et comporte des traitements : une classe ”Chaussure” d´crit, par exemple, e les caract´ristiques d’une chaussure. Elle contient un champ d´crivant la e e pointure, la couleur, la mati`re etc. Une telle classe comporte de plus des e traitements sur ces donn´es ; ces traitements sont appel´s ”m´thodes”. Grose e e si`rement une m´thode est une fonction appliqu´e a un objet. e e e ` Une fois d´finie une telle classe, il est possible d’en construire des inse tances : une instance d’une classe est dite ˆtre un objet de cette classe. Dans e notre exemple, il s’agirait d’une chaussure dont la pointure, la couleur et la mati`re sont renseign´es. e e

14.2

Pr´paratifs e

Nous allons maintenant voir comment ´crire une classe en Perl. Vous e verrez, cela est tr`s simple et d´mystifie la programmation objet. e e En Perl, une classe n’est autre qu’un module et un objet (instance de cette classe) n’est autre qu’une r´f´rence associ´e a cette classe. Dans le ee e ` constructeur, nous allons donc cr´er une r´f´rence (typiquement vers une e ee table de hachage) et nous allons l’associer au package en question ; lors de cette association, on dit en Perl que l’on b´nit (bless en anglais) la r´f´rence. e ee Les champs de l’objet seront en fait stock´s dans cette table de hachage, e sous forme de la clef pour le nom du champ et de la valeur pour la valeur du champ. Voyons un exemple : d´finissons une classe Vehicule qui comporte deux e champs : un nombre de roues et une couleur.

14.3

´ Ecrire un constructeur

Nous d´finissons un package Vehicule dans un fichier Vehicule.pm e comme nous le faisons pour tout module. 1: 2: 3: # --- fichier Vehicule.pm --package Vehicule; use strict; 144

c sylvain@lhullier.org

Introduction a la programmation en Perl `

4: 5: 6: 7: 8: 9: 10: 11: 12: 13:

sub new { my ($class,$nbRoues,$couleur) = @_; my $this = {}; bless($this, $class); $this->{NB_ROUES} = $nbRoues; $this->{COULEUR} = $couleur; return $this; } 1; # ` ne pas oublier... A

La ligne num´ro 2 indique le nom du package actuel ; il est conseill´ de e e choisir le mˆme nom que pour le fichier, simplement pour des raisons d’orgae nisation et de maintenance. La ligne 13 comporte le fameux code de retour du chargement du module. La ligne 3 force une syntaxe plus rigoureuse. En Perl, le nom des modules et donc des classes que le programmeur d´finit e doit ˆtre compos´ de majuscules et de minuscules, avec typiquement une e e majuscule au d´but de chaque mot ; les noms de package exclusivement en e minuscules sont r´serv´s pour les modules pragmatiques de Perl (dits moe e dules pragma comme strict etc), les noms exclusivement en majuscules sont in´l´gants. :-) ee Nous d´finissons une fonction new (ligne 4) dont le but est de construire e un objet Vehicule. Il s’agit donc d’un constructeur ; un constructeur en Perl est une simple fonction renvoyant un objet. Il est bon de noter que le choix du nom pour cette fonction est totalement libre ; il est courant de l’appeler new mais rien ne nous y oblige. On pourrait par exemple choisir le nom de la classe (si on est un habitu´ de C++ ou de Java), mais on verra par la e suite que cela n’est pas forc´ment une bonne id´e. e e Cette fonction prend en premier param`tre le nom de la classe ; cela e semble superflu, mais on verra qu’il n’en est rien. Les param`tres suivants e sont laiss´s a la discr´tion du programmeur : bien souvent on passe ici les e ` e valeurs de champs pour l’initialisation. C’est ce que l’on fait ici : le nombre de roues et la couleur sont transmis (ligne 6). Ligne 7, nous cr´ons une r´f´rence anonyme vers une table de hachage e ee vide {}. Cette r´f´rence est stock´e dans une variable scalaire nomm´e $this ee e e car il va s’agir de notre futur objet. Le nom de cette variable est totalement arbitraire et j’ai choisi de prendre le nom $this car il rappelle les variables this de C++ et de Java. Mais comprenez bien qu’il n’y a rien d’obligatoire dans cette appellation. Il est d’ailleurs fr´quent que le nom de l’objet dans les e m´thodes soit plutˆt $self en Perl (vous trouverez ce nom dans la plupart e o 145

Introduction a la programmation en Perl `

c sylvain@lhullier.org

des modules objet de CPAN). Ligne 8, nous indiquons que cette r´f´rence est li´e au package (` la ee e a classe) $class. Cette variable $class vaudra ici Vehicule. L’op´rateur e bless associe le package en question a la r´f´rence. La r´f´rence est main` ee ee tenant li´e au package. e Dans les lignes 9 et 10, les champs NB_ROUES et COULEUR sont initialis´s. e Le champ d’un objet n’est rien d’autre qu’une entr´e dans la table de hachage e qui constitue l’objet. Pour affecter un champ de l’objet que nous sommes en train de construire, il suffit de cr´er un couple clef/valeur dans la table e de hachage r´f´renc´e par $this. J’ai pris l’habitude de mettre le nom des ee e champs en lettres majuscules. Notez que le nombre, le nom et le contenu des champs peuvent donc varier d’une instance de la classe a une autre instance de cette mˆme classe. ` e Libre au programmeur de faire ce qu’il veut : si le but est de vraiment programmer objet de fa¸on formelle, il va respecter les habitudes de ce type de c programmation qui veut que toutes les instances d’une mˆme classe aient e les mˆmes champs ; mais s’il ne tient pas a respecter ces contraintes, il est e ` libre de faire ce qu’il veut de chacun de ses objets. La ligne 11 consiste en un return de la r´f´rence vers la table de hachage ee ainsi construite.

14.4

Appeler le constructeur

Pour faire usage de cette classe, nous allons devoir disposer d’un script ´crit dans un autre fichier (par exemple script.pl) : e #!/usr/bin/perl -w use strict; Comme pour tout module, nous devons explicitement indiquer que nous allons l’utiliser : use Vehicule; Nous pouvons maintenant utiliser le constructeur que nous avons d´fini : e my $v = Vehicule->new( 2, "bleu" ); my $v2 = Vehicule->new( 4, "rouge" ); Nous venons ici de cr´er deux instances de la classe Vehicule. On dit e que ces deux variables $v et $v2 sont des Vehicule. Ces deux objets sont 146

c sylvain@lhullier.org

Introduction a la programmation en Perl `

donc ind´pendants l’un de l’autre ; ils sont de la mˆme classe Vehicule, mais e e en constituent des instances autonomes, la modification de l’un ne modifiant pas l’autre. Voici un sch´ma de l’´tat de notre m´moire : e e e

$v

Vehicule NB_ROUES COULEUR => => 2 bleu

$v2

Vehicule NB_ROUES COULEUR => => 4 rouge

Cette syntaxe Vehicule->new correspond a l’appel du constructeur new ` que nous venons d’´crire. La variable $v est initialis´e a la valeur de retour e e ` de cette fonction. Elle est donc une r´f´rence vers une table de hachage dont ee deux champs sont initialis´s et qui a ´t´ b´nie (bless) en Vehicule. Idem e ee e pour $v2. Il est aussi possible de faire usage de la syntaxe suivante : my $v = new Vehicule( 2, "bleu" ); Cette formulation va sans doute rassurer les habitu´s de Java ou de e C++, mais peut induire le programmeur en erreur. En effet, cette derni`re e syntaxe semble indiquer que new est un op´rateur sp´cifique pour appeler un e e constructeur et est donc un mot r´serv´ du langage. Il n’en est rien ; comme e e on le verra un peu plus loin, ce nom est totalement arbitraire.

14.5

Manipulations de l’objet

Revenons a notre exemple. En plus de savoir qu’elle pointe vers une ` table de hachage, la r´f´rence $v sait de quelle classe elle est. En effet, si ee nous l’affichons : print "$v\n"; 147

Introduction a la programmation en Perl ` Nous obtenons la chose suivante a l’´cran : ` e

c sylvain@lhullier.org

Vehicule=HASH(0x80f606c) Je vous rappelle que dans le cas de l’affichage d’une r´f´rence vers une ee table de hachage non b´nie, nous obtenons quelque chose de la forme : e

HASH(0x80fef74) Un objet (` partir de maintenant nommons ainsi une r´f´rence vers une a ee table de hachage b´nie) sait donc de quelle classe il est. Cela va lui permettre e de choisir le bon package quand on appelera une m´thode sur cet objet (lire e la suite). Voyons maintenant ce que donne le module Data::Dumper (dont j’ai d´j` ea parl´) sur une telle r´f´rence : e ee

use Data::Dumper; print Dumper($v)."\n"; L’affichage suivant est effectu´ : e

$VAR1 = bless( { ’COULEUR’ => ’bleu’, ’NB_ROUES’ => 2 }, ’Vehicule’ ); On remarquera que la tradition de Data::Dumper qui consiste en ce que la chaˆ renvoy´e est directement int´grable dans un code Perl est ıne e e respect´e : mˆme l’op´ration de b´n´diction (bless) est pr´sente. e e e e e e Il faut bien voir que $v est une r´f´rence vers un objet. Autrement dit, ee si on fait une copie de cette variable

my $w = $v; 148

c sylvain@lhullier.org

Introduction a la programmation en Perl `

nous obtenons deux variables qui pointent vers le mˆme objet. e

$v

Vehicule NB_ROUES => => 2 bleu

$w COULEUR

$v2

Vehicule NB_ROUES COULEUR => => 4 rouge

La modification de l’objet point´ par l’un modifiera celui point´ par e e l’autre car il s’agit du mˆme objet. e

14.6

Plusieurs constructeurs

Comment ´crire plusieurs constructeurs pour une mˆme classe ? Rien e e de plus simple. Le nom new que j’ai choisi pour le constructeur n’a rien d’obligatoire, en fait un constructeur est une simple fonction qui renvoie une r´f´rence b´nie. Seule la syntaxe d’appel change par rapport a ce que ee e ` l’on a vu pour les modules. Je peux donc ´crire un autre constructeur (donc e avec un autre nom) : sub nouveau { my ($class,$couleur) = @_; my $this = {}; bless($this, $class); $this->{COULEUR} = $couleur; return $this; } Ce constructeur de Vehicule prend par exemple un seul param`tre (la e ` couleur) et n’affecte pas de champs NB_ROUES car rien de ne l’y oblige. A moi 149

Introduction a la programmation en Perl `

c sylvain@lhullier.org

de savoir comment je veux g´rer mes v´hicules, a savoir comment j’autorise e e ` qu’ils soient construits. Pour ˆtre propre et coh´rent, nous allons tout de mˆme consid´rer qu’il e e e e est sage d’affecter une valeur a la clef NB_ROUES : ` sub nouveau { my ($class,$couleur) = @_; my $this = {}; bless($this, $class); $this->{NB_ROUES} = 0; $this->{COULEUR} = $couleur; return $this; } Voici comment on va faire appel a ce constructeur : ` my $v2 = Vehicule->nouveau( "bleu" ); De la mˆme fa¸on que pour le pr´c´dent constructeur, il est possible e c e e d’utiliser la syntaxe suivante : my $v2 = nouveau Vehicule( "bleu" ); Ce qui est, reconnaissons-le, quelque peu d´routant. C’est pour cela que e je vous conseille d’utiliser plutˆt la premi`re syntaxe Vehicule->nouveau() o e ou alors de vous en tenir a un constructeur new pour ´crire new Vehicule(). ` e

14.7

´ Ecrire une m´thode e

Une m´thode est une fonction qui s’applique a une instance de la classe. e ` Cela est vrai dans tous les langages objet, mais bien souvent cela est masqu´ ; e dans notre cas rien de masqu´, le premier param`tre de la fonction sera e e l’objet (la r´f´rence b´nie) : ee e sub roule { my ($this,$vitesse) = @_; print "Avec $this->{NB_ROUES} roues, je roule a $vitesse.\n"; ` } 150

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Cette fonction d´clar´e dans le fichier Vehicule.pm a donc pour premier e e param`tre l’objet sur lequel elle est appel´e. Vous noterez une fois de plus e e que rien n’oblige le programmeur a nommer cette variable $this ; la seule ` contrainte est sa premi`re place parmi les arguments. e Cette m´thode peut d`s maintenant ˆtre appel´e depuis le fichier e e e e script.pl sur les objets de type Vehicule. Il n’y pas de n´cessit´ de faire e e usage du lourd m´canisme d’Exporter car nous n’avons pas besoin de moe difier l’espace de nom des fonctions des scripts appelant. Pour appeler la m´thode, il suffit d’´crire dans le fichier script.pl : e e $v->roule( 15 ); La fonction appel´e sera celle qui a pour nom roule d´finie dans le e e package li´ a la r´f´rence $v lors de sa b´n´diction. e` ee e e L’affichage suivant a donc lieu : Avec 2 roues, je roule a 15. ` ´ Ecrivons par exemple une m´thode d’affichage : e sub toString { my ($this) = @_; return "(Vehicule:$this->{NB_ROUES},$this->{COULEUR})"; } Cette m´thode renvoie une chaˆ de caract`res, repr´sentation de l’obe ıne e e jet. Les habitu´s de Java noterons que j’ai choisi le nom de cette fonction e pour leur rappeler des souvenirs, mais qu’il n’a rien de sp´cial. Voici come ment l’utiliser dans le script : print $v->toString()."\n"; Et l’affichage a lieu : (Vehicule:2,bleu) Libre a vous de choisir un plus bel affichage. ` 151

Introduction a la programmation en Perl `

c sylvain@lhullier.org

14.8

Reparlons des champs

Un champ est une donn´e propre a une instance de classe. En Perl, e ` ces champs sont stock´s comme clef/valeur dans la table de hachage qui e constitue l’objet (si on utilise une table de hachage comme objet, ce qui est souvent le cas). Nos v´hicules comportent deux champs : NB_ROUES et e COULEUR. Ces champs ´tant de simple clef/valeur d’une table de hachage dont on e dispose d’une r´f´rence dans le script, ils y sont accessibles. Dans le script, ee nous pouvons ´crire dans le fichier script.pl : e foreach my $k (keys %$v) { print "$k : $v->{$k}\n"; } C’est-`-dire que je peux acc´der sans restriction a l’ensemble des champs a e ` de l’objet. En effet, j’ai en main une r´f´rence vers une table de hachage ; ee le fait qu’elle soit b´nie ne change rien au fait que je peux la d´r´f´rencer e eee et acc´der aux diverses valeurs qu’elle contient. Je peux aussi bien modifier e ces valeurs ou mˆme en ajouter ou en supprimer, car il s’agit en effet d’une e table de hachage comme les autres. Comment prot´ger les donn´es d’un objet? allez-vous alors me demander. e e Et bien, Perl n’a rien pr´vu pour ca. Cela va sans doute faire hurler les e ¸ puristes de la programmation objet, mais c’est comme cela ... Perl vous propose les principaux m´canismes pour faire de la programmation objet e tout en restant coh´rent avec le reste du langage, certaines choses ne sont e donc pas possibles. Faute de champs priv´s en Perl, il existe une convention qui dit que e les champs dont la clef commence par un underscore (soulign´ _) sont des e champs priv´s et les scripts qui utilisent les objets ainsi faits sont pri´s de e e respecter cette convention. C’est le cas de beaucoup de modules CPAN. Cette convention est aussi valable pour les m´thodes (une m´thode dont le e e nom commence par une underscore est une m´thode priv´e). e e De fa¸on g´n´ral, un programmeur Perl est quelqu’un de bonne ´ducation c e e e (sinon il programmerait en Java ;-))) et il ne modifiera pas une instance d’une classe qu’il n’a pas ´crite. En effet, pourquoi modifier un objet Net::FTP e alors qu’il fait tr`s bien son travail? De toute fa¸on, il a forc´ment acc`s au e c e e code source de cette classe et s’il veut la modifier, il peut en faire une copie et la modifier ! 152

c sylvain@lhullier.org

Introduction a la programmation en Perl `

La protection des donn´es est donc plus une n´cessit´ sociale (manque de e e e confiance en l’esp`ce humaine a laquelle les d´veloppeurs pr´tendent encore e ` e e faire partie :-))) qu’une n´cessit´ technique. Pas dramatique pour faire de e e l’objet.

14.9

Composition

Prenons le temps de faire un petit exemple pratique pour illustrer le concept de composition. La composition est le fait qu’un objet est constitu´ e d’autres objets. Par exemple un garage comporte des v´hicules. e Je d´cide qu’un garage aura une taille limite : il s’agira du nombre maxie mal de v´hicules qu’il pourra contenir. Un garage devra donc contenir une e liste de v´hicules. e Nous devons cr´er un fichier Garage.pm contenant : e package Garage; use strict; # ... ici les m´thodes qui vont suivre e 1; Voyons ensuite le constructeur : sub new { my ($class,$places) = @_; my $this = {}; bless($this, $class); $this->{PLACES} = $places; $this->{VEHICULE} = []; return $this; } Ce constructeur prendra en param`tre le nombre de places disponibles e du garage ; cette valeur est enregistr´e dans le champ PLACES. Le champ e VEHICULE comportera la liste des v´hicules ; pour cela elle est initialis´e a e e ` la r´f´rence anonyme vers une liste vide. La m´thode ajoute se chargera ee e d’ajouter les v´hicules dans la limite du nombre de places : e sub ajoute { my ($this,$vehicule) = @_; 153

Introduction a la programmation en Perl ` if( @{$this->{VEHICULE}} < $this->{PLACES} ) { push @{$this->{VEHICULE}}, $vehicule; return 1; } return 0; }

c sylvain@lhullier.org

Cette m´thode prend en param`tre une r´f´rence vers un v´hicule. Elle e e ee e compare la longueur de la liste des v´hicules au nombre total de places e (l’expression @{$this->{VEHICULE}} est la liste point´e par la r´f´rence e ee $this->{VEHICULE} ; ´valu´e en contexte num´rique, elle vaut son nombre e e e d’´l´ments). S’il reste de la place, le v´hicule est ajout´ (fonction push) et ee e e elle renvoie vrai, sinon elle renvoie faux. Voici comment l’utiliser dans le script : use Garage; my $g = Garage->new(3); my $v = new Vehicule( 2, "bleu" ); $g->ajoute( $v ) or die("ajoute: plus de place"); $g->ajoute( Vehicule->new( 4, "vert" ) ) or die("ajoute: plus de place"); $g->ajoute( Vehicule->new( 1, "jaune" ) ) or die("ajoute: plus de place"); ´ Ecrivons maintenant une m´thode d’affichage pour un tel objet : e sub toString { my ($this) = @_; my $s = "{Garage:$this->{PLACES},"; foreach my $v ( @{$this->{VEHICULE}} ) { $s .= $v->toString(); } return $s."}"; } On appelle sur chaque objet Vehicule la m´thode toString de fa¸on a e c ` le faire apparaˆ dans la chaˆ que nous allons renvoyer. Voici comment ıtre ıne 154

c sylvain@lhullier.org

Introduction a la programmation en Perl `

appeler cette m´thode dans le script : e print $g->toString()."\n"; Ce qui donne l’affichage suivant : {Garage:3,(Vehicule:2,bleu)(Vehicule:4,vert)(Vehicule:1,jaune)} On pourrait ´crire cette m´thode diff´remment si on voulait s´parer e e e e chaque v´hicule par une virgule : e sub toString { my ($this) = @_; my $s = "{Garage:$this->{PLACES},"; $s .= join( ’,’, map( { $_->toString() } @{$this->{VEHICULE}} ) ); return $s."}"; } Ce qui donne l’affichage suivant : {Garage:3,(Vehicule:2,bleu),(Vehicule:4,vert),(Vehicule:1,jaune)} Pour ajouter encore une difficult´, je d´cide de trier les v´hicules par e e e nombre de roues croissant : sub toString { my ($this) = @_; my $s = "{Garage:$this->{PLACES},"; $s .= join( ’,’, map( {$_->toString()} sort( {$a->{NB_ROUES} <=> $b->{NB_ROUES} } @{$this->{VEHICULE}} ) ) ); return $s."}"; } Ce qui donne l’affichage suivant : {Garage:3,(Vehicule:1,jaune),(Vehicule:2,bleu),(Vehicule:4,vert)} Ces deux derniers exemples vous sont propos´s pour que vous vous tore turiez un peu les m´ninges ;-)) e 155

Introduction a la programmation en Perl `

c sylvain@lhullier.org

14.10

Destruction d’un objet

Un objet est d´truit d`s qu’aucune r´f´rence ne pointe vers cet objet. e e ee La ligne suivante, par exemple, lib`re la place m´moire occup´e par l’objet e e e Vehicule r´f´renc´ par $v2 : ee e $v2 = undef; ` A cet instant, Perl se rend compte que l’objet en question n’est plus accessible, la m´moire sera donc automatiquement lib´r´e par le m´canisme e ee e du garbage collector. La mˆme chose a lieu dans le cas de la disparition d’une variable locale : e if( ..... ) { my $v3 = Vehicule->new(3,’jaune’); ... ... } La variable $v3 cesse d’exister a la fermeture de l’accolade du if. L’objet ` qui a ´t´ cr´´ dans le bloc sera donc d´truit (sauf si on a fait en sorte qu’une e e ee e autre variable dont la visibilit´ d´passe ce bloc pointe aussi vers l’objet). e e Cette lib´ration n’est peut-ˆtre pas faite en temps r´el, mais ce n’est pas e e e au programmeur de s’en occuper. Il existe une m´thode tr`s sp´ciale, dont le nom est r´serv´, qui est ape e e e e pel´e lors de la destruction d’une instance d’un objet. Il s’agit de la m´thode e e DESTROY. Cette m´thode sera appel´e (si elle existe dans la classe) par le gare e bage collector juste avant la lib´ration de la m´moire de l’objet. e e sub DESTROY { my ($this) = @_; print "` la casse Vehicule ! "; A print "($this->{NB_ROUES} $this->{COULEUR})\n"; } Cette m´thode doit ˆtre d´finie dans le package de l’objet en question et e e e re¸oit en premier argument une r´f´rence vers l’objet qui va ˆtre d´truit. c ee e e Cette m´thode est tr`s utile pour lib´rer des ressources (fichier, connexion e e e r´seau etc) qui ont ´t´ allou´es lors de la cr´ation de l’objet. e ee e e 156

c sylvain@lhullier.org

Introduction a la programmation en Perl `

14.11

H´ritage e

L’h´ritage est un des apports de la programmation objet. Perl dispose e de tout ce qu’il faut pour le mettre en œuvre. Imaginons qu’en plus de v´hicules, nous avons besoin de manipuler des e v´los et des voitures. Ces objets ont en commun d’avoir un nombre de roues e et une couleur. Ils ont des caract´ristiques suppl´mentaires qui leur sont e e propres ; les v´los ont un nombre de vitesses et les voitures, un nombre de e si`ges. Ces classes Velo et Voiture vont donc h´riter de la classe Vehicule, e e c’est-`-dire qu’elles vont comporter tous les champs et les m´thodes de cette a e classe. On dit alors que la classe Vehicule est la classe m`re ; les classes Velo e et Voiture ´tant des classes filles. Notez bien que je prends comme exemple e deux classes filles et qu’il n’est nullement n´cessaire d’avoir deux classes filles e pour mettre en œuvre l’h´ritage, une seule est suffisante. e Voyons le cas de la classe Velo, cr´ons pour cela un fichier Velo.pm qui e contient : package Velo; use strict; use Vehicule; our @ISA = qw(Vehicule); # ... ici les m´thodes qui vont suivre e 1; On signale le lien de filiation entre classes au moyen de la variable @ISA positionn´e a la valeur d’une liste contenant le nom de la classe m`re. ISA e ` e vient de l’anglais ”is a”, est un : on dit qu’un v´lo est un v´hicule. Il h´rite e e e donc des champs et m´thodes de la classe Vehicule. e D´finissons lui un constructeur : e sub new { my ($class,$couleur,$nbVitesses) = @_; my $this = $class->SUPER::new( 2, $couleur ); $this->{NB_VITESSES} = $nbVitesses; return bless($this,$class); } 157

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Ce constructeur prend donc deux param`tres. Il appelle le construce teur de la classe m`re (syntaxe $class->SUPER::new). Il ajoute un champ e NB_VITESSE et renvoie une r´f´rence b´nie en Velo. Notez bien qu’aucun ee e appel au constructeur de la classe m`re n’est fait par d´faut, il faut le faire e e explicitement dans tous les cas. Le lecteur aura not´ que, comme les champs de la classe m`re et de la e e classe fille sont stock´s dans la mˆme table de hachage, il n’y a pas moyen e e simple de faire de surcharge ou de masquage des champs. Les noms des champs devront ˆtre minutieusement choisis pour ne pas entrer en conflit e les uns avec les autres. Voyons a pr´sent comment ´crire une m´thode pour cet objet : ` e e e sub pedale { my ($this,$ici) = @_; print "Sur mon v´lo $this->{COULEUR} "; e print "je p´dale avec $this->{NB_VITESSES} vitesses"; e print " dans $ici.\n"; } Utilisons maintenant tout cela dans notre script : use Velo; my $velo = Velo->new(’blanc’,18); $velo->pedale(’les bois’); $velo->roule(10); Un v´lo dispose de la m´thode roule car il est aussi un v´hicule. L’affie e e chage suivant est effectu´ : e Sur mon v´lo blanc je p´dale avec 18 vitesses dans les bois. e e Avec 2 roues, je roule a 10. ` Voyons a pr´sent comment afficher un tel objet. Nous laisserons le soin ` e a la classe Vehicule d’afficher le v´lo comme ´tant un v´hicule et nous ` e e e n’effectuerons dans la classe Velo que l’affichage de ce que nous avons ajout´ e a la classe m`re : ` e sub toString { my ($this) = @_; my $s = "[Velo:$this->{NB_VITESSES}"; 158

c sylvain@lhullier.org

Introduction a la programmation en Perl `

$s .= $this->SUPER::toString(); $s .= "]"; } La syntaxe $this->SUPER::toString() correspond a l’appel de la m´thode ` e toString de la classe m`re. Nous pouvons maintenant l’appeler dans notre e script : print $velo->toString()."\n"; L’affichage suivant est effectu´ : e [Velo:18(Vehicule:2,blanc)] Rien de plus simple ! Seule chose pas extrˆmement pratique, l’appel au destructeur s’arrˆte e e au premier destructeur rencontr´. Si dans notre exemple nous d´finissions e e une m´thode DESTROY pour la classe Velo, la m´thode DESTROY de la classe e e Vehicule ne sera pas appel´e. Cela peut ˆtre gˆnant si des ressources impore e e tantes sont lib´r´es dans cette m´thode ; il faut alors l’appeler explicitement. ee e Voici un exemple de m´thode DESTROY pour la classe Velo : e sub DESTROY { my ($this) = @_; $this->SUPER::DESTROY(); print "Bye bye Velo ! "; print "($this->{NB_VITESSES} $this->{NB_ROUES} ". "$this->{COULEUR})\n"; } La deuxi`me ligne de la m´thode fait un appel a la m´thode de la classe e e ` e m`re. e Pour faire de l’h´ritage multiple en Perl, rien de plus simple. Vous aurez e peut-ˆtre not´ que la variable @ISA est un tableau, elle peut donc contenir e e plusieurs noms de classe : package Voiture; our @ISA = qw(Vehicule Danger Pollution); La d´termination de la bonne m´thode a appeler est effectu´e dynae e ` e miquement par une recherche en profondeur dans l’arbre d’h´ritage. Je ne e m’´tendrai pas plus sur cette question de l’h´ritage multiple. e e 159

Introduction a la programmation en Perl `

c sylvain@lhullier.org

14.12

Classes d’un objet

Dans cette partie nous allons voir comment connaˆ la classe d’un objet ıtre ainsi que tester l’appartenance a une classe pour un objet. ` Souvenez-vous de l’op´rateur ref qui, appliqu´ a une r´f´rence, renvoie e e` ee le type de structure de donn´es vers laquelle elle pointe (scalaire, tableau, e table de hachage etc). Appliqu´ a un objet, il renvoie la classe de l’objet : e` print ref($velo)."\n"; print "Ouf, tout va bien !\n" if( ref($velo) eq "Velo" ); L’affichage effectu´ est le suivant : e Velo Ouf, tout va bien ! Il s’agit donc de la classe ”principale” de l’objet. Sachant qu’un v´lo e est aussi un v´hicule, il peut ˆtre utile de pouvoir tester l’appartenance de e e l’objet a une classe plutˆt que de connaˆ sa classe principale. Par exemple, ` o ıtre si nous manipulons un tableau comportant des objets divers et vari´s et si e nous souhaitons y retrouver tous les objets de classe Vehicule pour appeler leur m´thode roule, nous ne pouvons pas ´crire e e if( ref($r) eq "Vehicule" ) { ... } car les v´los ne seront pas s´lectionn´s. En fait la question que nous e e e devons ici nous poser n’est pas de savoir si la classe principale de l’objet est Vehicule, mais nous devons nous demander si l’objet est un objet de classe Vehicule (ce qui est vrai pour tout objet de classe Vehicule et ses sousclasses, comme Velo et Voiture). La fonction isa du package UNIVERSAL va nous permettre de faire cela : use UNIVERSAL qw(isa); if( isa( $r, "Vehicule" ) ) { $r->roule( 40 ); } On teste ainsi si la variable $r est un objet de classe Vehicule. 160

c sylvain@lhullier.org

Introduction a la programmation en Perl `

14.13

Champs et m´thodes statiques e

Un champ statique est un champ qui est commun a tous les objets d’une ` classe, c’est-`-dire qu’il n’est pas li´ a une instance particuli`re mais a une a e` e ` classe. C’est une sorte de variable globale (dont l’acc`s peut ´ventuellement e e ˆtre contrˆl´) qui est situ´e dans une classe. e oe e Pour faire cela en Perl, nous utiliserons des variables d´clar´es dans le e e package de la classe en question. package Vehicule; my $privateVar = 0; our $publicVar = "hello"; Avec le qualificateur my, nous d´clarons des variables priv´es (car visibles e e uniquement depuis l’int´rieur du package). Avec our, sont d´clar´es des e e e variables publiques (accessibles depuis n’importe quel package). Je rappelle que pour acc´der a la variable $publicVar du package e ` Vehicule, on doit ´crire $Vehicule::publicVar ; depuis les fonctions et e m´thodes de ce package, il est suffisant d’´crire $publicVar (sauf masquage e e par une variable locale). On pourrait par exemple compter le nombre de v´hicules cr´´s au moyen e ee d’une telle variable : package Vehicule; my $nbVehicules = 0; sub new { my ($class,$nbRoues,$couleur) = @_; my $this = {}; bless($this, $class); $this->{NB_ROUES} = $nbRoues; $this->{COULEUR} = $couleur; $nbVehicules++; # un v´hicule de plus e return $this; } ` A chaque appel au constructeur de cette classe, la variable $nbVehicules sera donc incr´ment´e. e e Maintenant, comment ´crire une m´thode statique ? Une m´thode stae e e tique (ou m´thode de classe) est une m´thode qui n’est pas appel´e sur une e e e instance de la classe (donc pas de variable $this) mais pour toute la classe. 161

Introduction a la programmation en Perl `

c sylvain@lhullier.org

Ce n’est ni plus ni moins qu’une brave fonction pr´sente dans le package. e Cette fonction pourra donc uniquement acc´der aux champs statiques de la e classe. Nous pourrions, par exemple, ´crire une m´thode statique qui renvoie le e e nombre de v´hicules cr´´s (variable $nbVehicules) : e ee sub getNbVehicules { my ($class) = @_; return $nbVehicules; } On notera que la m´thode prend en premier argument le nom de la classe. e Cela a pour cons´quence que l’appel a la m´thode ne se fait pas tout a fait e ` e ` comme pour une fonction d’un package (comme vu pour les modules), mais de la mani`re suivante : e print Vehicule->getNbVehicules()."\n"; Le nom de la classe est suivi d’une fl`che, du nom de la m´thode et des e e ´ventuels arguments entre parenth`ses. N’´crivez pas e e e Vehicule::getNbVehicules() car le nom de la classe n’est pas transmis et surtout car les m´canismes d’h´ritage ne sont pas mis en œuvre. S’il e e est possible d’´crire Velo->getNbVehicules(), il n’est pas permis d’´crire e e Velo::getNbVehicules(). Le lecteur notera que les constructeurs sont des m´thodes statiques. Ils e retournent des r´f´rences b´nies, mais n’ont rien de particulier par rapport ee e a d’autres m´thodes de classe. ` e Il est tout a fait possible d’appeler cette m´thode sur une instance de la ` e classe Vehicule print $v->getNbVehicules()."\n"; mais dans ce cas le premier argument re¸u n’est pas le nom de la classe c mais l’objet en question (c’est donc une m´thode d’instance et de classe ...). e Cela ne change rien pour notre m´thode getNbVehicules car elle n’utilise e pas son premier argument, mais le cas est gˆnant pour les constructeurs e qui ont a b´nir une r´f´rence. Pour cela, tout constructeur devrait commen` e ee cer par d´terminer s’il a en premier argument le nom de la classe ou une e r´f´rence. L’instruction qui suit place dans la variable $class la classe acee tuelle, que cette variable ait pour valeur initiale le nom de la classe ou une instance de la classe : $class = ref($class) || $class; 162

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Il convient dor´navant d’´crire le constructeur ainsi : e e sub new { my ($class,$nbRoues,$couleur) = @_; $class = ref($class) || $class; my $this = {}; bless($this, $class); $this->{NB_ROUES} = $nbRoues; $this->{COULEUR} = $couleur; $nbVehicules++; # un v´hicule de plus e return $this; } Il est maintenant possible d’´crire la ligne suivante dans le script : e $v2 = $v->new( 1, "noir" ); Le constructeur est appel´ sur une instance de la classe plutˆt que sur la e o classe. On pourrait faire de mˆme pour toutes les m´thodes statiques (c’est e e mˆme plutˆt conseill´). e o e

14.14

Exemple complet

Voici le contenu exact des fichiers d’exemple bˆtis tout au long de cette a partie du document. Fichier Vehicule.pm : package Vehicule; use strict; my $nbVehicules = 0; sub new { my ($class,$nbRoues,$couleur) = @_; $class = ref($class) || $class; my $this = {}; bless($this, $class); $this->{NB_ROUES} = $nbRoues; $this->{COULEUR} = $couleur; $nbVehicules++; # un v´hicule de plus e return $this; 163

Introduction a la programmation en Perl `

c sylvain@lhullier.org

} sub roule { my ($this,$vitesse) = @_; print "Avec $this->{NB_ROUES} roues, je roule a $vitesse.\n"; ` } sub toString { my ($this) = @_; return "(Vehicule:$this->{NB_ROUES},$this->{COULEUR})"; } sub getNbVehicules { my ($class) = @_; $class = ref($class) || $class; return $nbVehicules; } sub DESTROY { my ($this) = @_; print "Bye bye Vehicule ! "; print "($this->{NB_ROUES} $this->{COULEUR})\n"; } 1; # ` ne pas oublier... A Fichier Velo.pm : package Velo; use strict; use Vehicule; our @ISA = qw(Vehicule); sub new { my ($class,$couleur,$nbVitesses) = @_; $class = ref($class) || $class; my $this = $class->SUPER::new( 2, $couleur ); $this->{NB_VITESSES} = $nbVitesses; return bless($this,$class); } sub pedale { 164

c sylvain@lhullier.org

Introduction a la programmation en Perl `

my ($this,$ici) = @_; print "Sur mon v´lo $this->{COULEUR} "; e print "je p´dale avec $this->{NB_VITESSES} vitesses"; e print " dans $ici.\n"; } sub toString { my ($this) = @_; my $s = "[Velo:$this->{NB_VITESSES}"; $s .= $this->SUPER::toString(); $s .= "]"; } sub DESTROY { my ($this) = @_; $this->SUPER::DESTROY(); print "Bye bye Velo ! "; print "($this->{NB_VITESSES} $this->{NB_ROUES} ". $this->{COULEUR})\n"; } 1; Fichier Garage.pm : package Garage; use strict; sub new { my ($class,$places) = @_; $class = ref($class) || $class; my $this = {}; bless($this, $class); $this->{PLACES} = $places; $this->{VEHICULE} = []; return $this; } sub ajoute { my ($this,$vehicule) = @_; if( @{$this->{VEHICULE}} < $this->{PLACES} ) { 165

Introduction a la programmation en Perl ` push @{$this->{VEHICULE}}, $vehicule; return 1; } return 0; } sub toString { my ($this) = @_; my $s = "{Garage:$this->{PLACES},"; $s .= join( ’,’, map( {$_->toString()} sort( {$a->{NB_ROUES} <=> $b->{NB_ROUES} } @{$this->{VEHICULE}} ) ) ); return $s."}"; } 1; Fichier script.pl : #!/usr/bin/perl -w use strict; use Data::Dumper; use UNIVERSAL qw(isa); use Vehicule; use Garage; use Velo; my $v = Vehicule->new( 2, "bleu" ); my $v2 = Vehicule->new( 4, "rouge" ); print "$v\n"; print Dumper($v)."\n"; $v->roule(30); $v2 = undef; if( 1 ) { my $v3 = Vehicule->new(3,’jaune’); } foreach my $k (keys %$v) { print "$k : $v->{$k}\n"; } print $v->toString()."\n";

c sylvain@lhullier.org

166

c sylvain@lhullier.org

Introduction a la programmation en Perl `

my $g = Garage->new(3); $g->ajoute( $v ) or die("ajoute: plus de $g->ajoute( Vehicule->new( or die("ajoute: plus de $g->ajoute( Vehicule->new( or die("ajoute: plus de print $g->toString()."\n"; my @tab = (

place"); 4, "vert" ) ) place"); 1, "jaune" ) ) place");

Velo->new(’rose’,15), Vehicule->new(3,’gris’), "hello", Velo->new(’vert’,21), ); foreach my $r (@tab) { if( isa( $r, "Vehicule" ) ) { $r->roule( 40 ); } } my $velo = Velo->new(’blanc’,18); $velo->pedale(’les bois’); $velo->roule(10); print $velo->toString()."\n"; print ref($velo)."\n"; print "Ouf, tout va bien !\n" if( ref($velo) eq "Velo" ); print Vehicule->getNbVehicules()."\n"; print Velo->getNbVehicules()."\n"; print $v->getNbVehicules()."\n"; $v2 = $v->new( 1, "noir" );

167

Introduction a la programmation en Perl `

c sylvain@lhullier.org

168

c sylvain@lhullier.org

Introduction a la programmation en Perl `

Conclusion
Nous sommes ici au terme de ce cours introductif a la programmation en ` Perl. Vous avez maintenant en main la plupart des concepts et des notions pour ˆtre autonome en Perl. e N’oubliez pas que la documentation de Perl est tr`s bien faite et est dispoe nible sur votre ordinateur au moyen de la commande perldoc : perldoc perl vous donne acc`s a la liste des th`mes consultables avec perldoc. Par e ` e exemple perldoc perldata vous explique les structures de donn´es en Perl. e Pour une fonction particuli`re, utilisez l’option -f : perldoc -f chomp Pour e un module particulier, utilisez perldoc sans option : perldoc Data::Dumper Vous avez maintenant en main beaucoup de notions importantes de Perl. ` A vous de les mettre en œuvre pour vos propres probl`mes. Il n’est pas e forcement facile d’exprimer son besoin en termes directement exploitable dans un langage particulier, mais en ayant un peu d’exp´rience de Perl, e vous trouverez vite votre mani`re de r´soudre un probl`me. Vous allez alors e e e commencer a faire connaissance avec Tim Towtdi (There is more than one ` way to do it). ;-)

169

Introduction a la programmation en Perl `

c sylvain@lhullier.org

170

c sylvain@lhullier.org

Introduction a la programmation en Perl `

L’auteur
Sylvain Lhullier <sylvain@lhullier.org> http://www.lhullier.org/ ` A l’Universit´ de Marne-la-Vall´e (http://www.univ-mlv.fr/), il est e e charg´ chaque ann´e d’un module complˆt d’enseignement en maˆ e e e ıtrise informatique ; ce module porte sur des sujets tels que Perl, Perl/Tk, Perl/DBI, Apache, CGI/Perl et consiste en dix semaines d’un cours en amphith´atre e et de trois travaux dirig´s, ainsi qu’en un examen final et un projet. e Il travaille pour Linagora (http://www.linagora.com/) comme consultant formateur et d´veloppeur ; il intervient principalement pour des projets e et prestations concernant le d´veloppement (Perl, Java, C++, programmae tion syst`me, PHP, Apache, MySQL, XML etc.). e Il a d´velopp´ chez feue-Atrid des projets bˆtis en Perl (LogTrend, Mioga) e e a et publi´s sous GPL. e Il a donn´ une conf´rence ”Perl : pour quoi faire?” lors du salon Linuxe e Solutions de janvier 2004. Entre autres associations, il est membre et administrateur de l’association ”Les Mongueurs de Perl” dont l’objet est de promouvoir le langage Perl en France par des r´unions, des conf´rences etc (http://www.mongueurs.net/). e e Il y coordonne le groupe de travail ”Articles” dont le but est de publier un article dans la presse francophone technique, notamment dans GNU/Linux & Hurd Magazine France (http://www.linuxmag-france.org/) chaque mois. L’auteur tient a remercier tr`s chaleuseusement les autres membres de l’as` e sociation pour leur aide, leur soutien et les relectures effectu´es. e

171