Vous êtes sur la page 1sur 1078

customer_8566

Programmation
en PERL

I l y a p l u s d u n e fa o n d e fa i re

Traduction de Philippe Bruhat, Kai Carver et Grald Sdrati

De Larry Wall, Tom Christiansen et Jon Orwant

customer_8566

A Maymak, GDGN, le philosophe de la Npalawi et Larabs


Pirate de Bard

customer_8566

Programmation en Perl

customer_8566

LARRY WALL, TOM CHRISTIANSEN et JON ORWANT

Programmation en Perl
Traduction de Philippe Bruhat, Kai Carver et Grald Sdrati

Digit Books diteur de livres numriques Brest infos@digitbooks.fr http://www.digitbooks.fr

customer_8566

Digit Books, 2009, pour la traduction franaise ISBN : 978-2-8150-0172-4 Prix : 35

OReilly Media , 2005 Ldition originale de ce livre a t publie aux tats-Unis par OReilly Media sous le titre Programming Perl, 3rd edition, ISBN 0-596-00027-.

Couverture : Yves Buraud Illustration de Ptit-Bonhomme de Jules Verne (1893) par Lon Benett.

http://www.digitbooks.fr/catalogue/9782815001724.html

Les programmes figurant dans ce livre ont pour but dillustrer les sujets traits. Il nest donn aucune garantie quant leur fonctionnement une fois compils, assembls ou interprts dans le cadre dune utilisation professionnelle ou commerciale.

Toute reprsentation ou reproduction, intgrale ou partielle, faite sans le consentement de lauteur, de ses ayants droit, ou ayants cause, est illicite (loi du 11 mars 1957, alina 1er de larticle 40). Cette reprsentation ou reproduction, par quelque procd que ce soit, constituerait une contrefaon sanctionne par les articles 425 et suivants du Code pnal. La loi du 11 mars 1957 autorise uniquement, aux termes des alinas 2 et 3 de larticle 41, les copies ou reproductions strictement rserves lusage priv du copiste et non destines une utilisation collective dune part et, dautre part, les analyses et les courtes citations dans un but dexemple et dillustration.

customer_8566

customer_8566

Table des matires

Prface ..................................................................................... xiii

I.
1.

SURVOL DE PERL ...................................................... 1


Vue densemble .................................................................... 3
Dmarrage ................................................................................................. 3 Langages naturels et artificiels ................................................................. 4 Un exemple de notation ......................................................................... 14 Handles de fichiers .................................................................................. 17 Oprateurs ................................................................................................ 19 Structures de contrle ............................................................................. 25 Expressions rgulires ............................................................................. 30 Traitement des listes ................................................................................ 36 Ce que vous ne savez pas ne vous fera pas (trop) de mal ..................... 38

II. SANCE DE DISSECTION ........................................... 39


2. Composants de Perl .......................................................... 41
Atomes ..................................................................................................... Molcules ................................................................................................. Types internes .......................................................................................... Variables ................................................................................................... Noms ........................................................................................................ Valeurs scalaires ...................................................................................... Contexte ................................................................................................... Valeur de liste et tableaux ...................................................................... Hachages .................................................................................................. 41 42 43 45 46 50 59 62 65

customer_8566

Table des matires

vi

Typeglobs et handles de fichiers ............................................................. 67 Oprateurs dentre ................................................................................. 68

3.

Oprateurs unaires et binaires ........................................ 75


Termes et oprateurs de listes (vers la gauche) ..................................... Loprateur flche ................................................................................... Auto-incrmentation et autodcrmentation ...................................... Exponentiation ........................................................................................ Oprateurs unaires idographiques ....................................................... Oprateurs de liaison .............................................................................. Oprateurs multiplicatifs ........................................................................ Oprateurs additifs .................................................................................. Oprateurs de dcalage ........................................................................... Oprateurs unaires nomms et de test de fichier ................................. Oprateurs relationnels .......................................................................... Oprateurs dgalit ................................................................................ Oprateurs sur les bits ............................................................................. Oprateurs logique de type C ( court-circuit) ..................................... Oprateur dintervalle ............................................................................. Oprateur conditionnel .......................................................................... Oprateurs daffectation ......................................................................... Oprateurs virgule ................................................................................... Oprateurs de liste (vers la droite) ......................................................... And, or, not et xor logiques .................................................................... Oprateurs C manquant en Perl ............................................................ 77 79 79 80 80 81 82 83 83 83 87 88 88 89 90 91 93 94 95 95 96

4.

Instructions et dclarations .............................................. 97


Instructions simples ................................................................................ 97 Instructions composes ........................................................................... 99 Instructions if et unless ......................................................................... 100 Instructions de boucle ........................................................................... 101 Blocs simples .......................................................................................... 108 goto ......................................................................................................... 111 Dclarations globales ............................................................................ 112 Dclarations avec porte ....................................................................... 114 Pragmas .................................................................................................. 120

5.

Recherche de motif ......................................................... 123


Bestiaire des expressions rgulires ..................................................... Oprateurs de recherche de motifs ...................................................... Mtacaractres et mtasymboles .......................................................... Classes de caractres .............................................................................. 124 126 141 148

customer_8566

Table des matires

vii

Quantificateurs ...................................................................................... Positions ................................................................................................. Capture et regroupement ..................................................................... Alternative ............................................................................................. Garder le contrle ................................................................................. Motifs tendus .......................................................................................

158 161 164 168 170 183

6.

Sous-programmes ............................................................ 197


Syntaxe ................................................................................................... Smantique ............................................................................................ Passage de rfrences ............................................................................. Prototypes .............................................................................................. Attributs de sous-programmes ............................................................. 197 199 203 205 210

7.

Formats ............................................................................ 213


Variables de format ............................................................................... 216 Pieds de page .......................................................................................... 218

8.

Rfrences ........................................................................ 221


Quest-ce quune rfrence ? ................................................................. Cration de rfrences .......................................................................... Utilisation des rfrences en dur .......................................................... Rfrences symboliques ........................................................................ Accolades, crochets et guillemets ......................................................... 221 223 229 241 242

9.

Structures de donnes ..................................................... 245


Tableaux de tableaux ............................................................................ Hachages de tableaux ............................................................................ Tableaux de hachages ............................................................................ Hachages de hachages ........................................................................... Hachages de fonctions .......................................................................... Enregistrements plus labors .............................................................. Sauvegarde de structures de donnes .................................................. 245 252 254 255 259 259 262

10. Paquetages ...................................................................... 265


Tables de symboles ................................................................................ 269 Autochargement .................................................................................... 273

11. Modules ............................................................................ 275


Utilisation des modules ........................................................................ 275 Cration de modules ............................................................................. 277 Supplanter des fonctions internes ....................................................... 281

customer_8566

Table des matires

viii

12. Objets ............................................................................... 283


Bref rappel de vocabulaire orient objet ............................................. Le systme objet de Perl ....................................................................... Invocation de mthode ......................................................................... Construction dobjet ............................................................................. Hritage de classe .................................................................................. Destructeurs dinstance ......................................................................... Gestion des donnes dinstance ........................................................... Gestion des donnes de classe .............................................................. Rsum ................................................................................................... 283 285 285 291 295 303 304 315 318

13. Surcharge ......................................................................... 319


Le pragma overload .............................................................................. Handlers de surcharge .......................................................................... Oprateurs surchargeables .................................................................... Le constructeur de copie (=) ................................................................. Lorsquun handler de surcharge fait dfaut (nomethod et fallback) Surcharge de constantes ........................................................................ Fonctions publiques de surcharge ....................................................... Hritage et surcharge ............................................................................ Surcharge lexcution ......................................................................... Surcharge de diagnostics ....................................................................... 320 320 322 328 329 330 332 332 333 333

14. Variables lies ................................................................. 335


Liaison de scalaire .................................................................................. Liaison de tableau ................................................................................. Liaison de hachage ................................................................................ Liaison de handle de fichier ................................................................. Un pige subtil du dliement ............................................................... Modules de liaison sur CPAN .............................................................. 337 344 349 355 366 368

III. TECHNIQUE PERL ................................................. 371


15. Unicode ............................................................................ 373
Construction dun caractre ................................................................. 374 Consquences de la smantique de caractre ..................................... 376 Attention au travail .............................................................................. 380

16. Communication interprocessus ...................................... 383


Signaux ................................................................................................... 384 Fichiers ................................................................................................... 390

customer_8566

Table des matires

ix

Pipes ....................................................................................................... 397 IPC System V ......................................................................................... 405 Sockets .................................................................................................... 409

17. Threads ............................................................................ 417


Le modle de processus ......................................................................... 418 Le modle de thread .............................................................................. 419

18. Compilation ..................................................................... 435


Cycle de vie dun programme Perl ...................................................... Compilation du code ............................................................................ Excution du code ................................................................................. Sorties du compilateur .......................................................................... Gnrateurs de code .............................................................................. Outils de dveloppement de code ........................................................ Compilateur davant-garde, interprteur rtro .................................. 436 437 443 446 447 449 450

19. Linterface de la ligne de commande ............................. 455


Traitement des commandes ................................................................. 455 Variables denvironnement .................................................................. 471

20. Le dbogueur Perl ........................................................... 475


Utilisation du dbogueur ..................................................................... Commandes du dbogueur .................................................................. Personnalisation du dbogueur ........................................................... Implmentation du dbogueur ........................................................... Le profileur Perl .................................................................................... 476 478 487 492 494

21. Mcanismes internes et accs externes .......................... 499


Comment fonctionne Perl ................................................................... Types de donnes internes .................................................................... tendre Perl (utiliser du C depuis du Perl) ......................................... Insrer Perl (utiliser Perl depuis C) ..................................................... Morale de lhistoire ............................................................................... 500 500 501 507 512

IV. CULTURE PERL ..................................................... 513


22. CPAN ............................................................................... 515
Le rpertoire modules de CPAN .......................................................... 516 Utilisation des modules de CPAN ....................................................... 520 Cration de modules pour CPAN ........................................................ 522

customer_8566

Table des matires

23. Scurit ............................................................................ 525


Gestion des donnes non sres ............................................................ 526 Gestion des problmes de synchronisation ......................................... 536 Gestion du code non sr ....................................................................... 543

24. Techniques couramment employes .............................. 553


tourderies courantes des dbutants ................................................... Erreurs universelles ............................................................................... Efficacit ................................................................................................. Programmation style ........................................................................... Perl avec aisance .................................................................................... Gnrer des programmes ...................................................................... 553 554 561 569 573 582

25. Portabilit ...................................................................... 587


Sauts de ligne ......................................................................................... Boutisme et taille des nombres ............................................................ Fichiers et systmes de fichiers ............................................................. Interactions avec le systme ................................................................. Communication interprocessus (IPC) ................................................. Sous-programmes externes (XS) ........................................................... Modules standard .................................................................................. Dates et heures ...................................................................................... Internationalisation .............................................................................. Style ........................................................................................................ 588 589 590 591 592 592 592 593 593 594

26. POD ................................................................................. 595


Pod en quelques mots ........................................................................... Traducteurs et modules pod ................................................................. crire vos propres outils pod ................................................................ Piges du pod ......................................................................................... Documenter vos programmes Perl ...................................................... 595 603 605 608 609

27. Culture Perl ..................................................................... 611


Lhistoire en pratique ............................................................................ 611 Posie en Perl ........................................................................................ 613

V. RFRENCES ......................................................... 617


28. Noms spciaux ................................................................. 619
Noms spciaux classs par type ............................................................ 619 Variables spciales dans lordre alphabtique .................................... 622

customer_8566

Table des matires

xi

29. Fonctions ......................................................................... 643


Fonctions Perl par catgorie ................................................................. 646 Fonctions Perl par ordre alphabtique ................................................ 647

30. La bibliothque standard Perl ....................................... 787


Bibliothquologie .................................................................................. 787 Visite guide de la bibliothque Perl ................................................... 789

31. Modules de pragmas ....................................................... 791


use attributes .......................................................................................... use autouse ............................................................................................. use base ................................................................................................... use blib ................................................................................................... use bytes ................................................................................................. use charnames ....................................................................................... use constant ........................................................................................... use diagnostics ....................................................................................... use fields ................................................................................................. use filetest ............................................................................................... use integer .............................................................................................. use less .................................................................................................... use lib ..................................................................................................... use locale ................................................................................................ use open ................................................................................................. use overload ........................................................................................... use re ...................................................................................................... use sigtrap .............................................................................................. use strict ................................................................................................. use subs ................................................................................................... use vars ................................................................................................... use warnings .......................................................................................... 792 793 794 795 795 795 796 798 800 803 803 804 804 806 807 807 808 809 812 814 814 815

32. Modules standards .......................................................... 819


Listes par type ........................................................................................ Benchmark ............................................................................................. Carp ........................................................................................................ CGI ......................................................................................................... CGI::Carp ............................................................................................... Class::Struct ............................................................................................ Config ..................................................................................................... CPAN ..................................................................................................... Cwd ......................................................................................................... Data::Dumper ........................................................................................ 819 831 833 833 834 835 836 836 837 837

customer_8566

xii

Table des matires

DB_File .................................................................................................. Dumpvalue ............................................................................................ English .................................................................................................... Errno ...................................................................................................... Exporter .................................................................................................. Fatal ........................................................................................................ Fcntl ........................................................................................................ File::Basename ....................................................................................... File::Compare ........................................................................................ File::Copy ............................................................................................... File::Find ................................................................................................ File::Glob ................................................................................................ File::Spec ................................................................................................ File::stat .................................................................................................. File::Temp .............................................................................................. FileHandle ............................................................................................. Getopt::Long .......................................................................................... Getopt::Std ............................................................................................. IO::Socket ............................................................................................... IPC::Open2 ............................................................................................. IPC::Open3 ............................................................................................. Math::BigInt ........................................................................................... Math::Complex ...................................................................................... Math::Trig .............................................................................................. Net::hostent ........................................................................................... POSIX ..................................................................................................... Safe ......................................................................................................... Socket ..................................................................................................... Symbol ................................................................................................... Sys::Hostname ....................................................................................... Sys::Syslog .............................................................................................. Term::Cap .............................................................................................. Text::Wrap ............................................................................................. Time::Local ............................................................................................ Time::localtime ...................................................................................... User::grent .............................................................................................. User::pwent ............................................................................................

838 839 840 840 841 842 842 843 843 844 845 845 848 849 849 850 853 854 854 855 856 857 857 858 858 859 861 862 863 864 864 866 866 867 868 868 869

33. Messages de diagnostic .................................................... 871 Glossaire ................................................................................... 947 Index ......................................................................................... 981

customer_8566

Prface

la poursuite du bonheur
Perl est un langage qui vous aide faire votre travail. Bien sr, si votre travail consiste programmer, vous pouvez le faire avec nimporte quel langage informatique complet , du moins en thorie. Mais nous savons par exprience que les langages informatiques ne diffrent pas tant par ce quils rendent possible que par ce quils rendent facile. Dun ct, les langages soi-disants de quatrime gnration facilitent certaines tches, mais en rendent dautres quasiment impossibles. De lautre ct, certains langages bien connus, de qualit industrielle , rendent peu prs tout difficile. Perl est diffrent. En rsum, Perl est conu pour simplifier les tches faciles, sans rendre les tches difficiles impossibles. Et quelles sont ces tches faciles qui devraient le rester ? Celles que lon rencontre tous les jours, bien sr. Il faut un langage qui facilite la manipulation des nombres, de texte, des fichiers et des rpertoires, des ordinateurs et des rseaux, et surtout des programmes. Il devrait tre facile de lancer des programmes externes et de scruter leur sortie la recherche dinformations intressantes. Il devrait tre facile denvoyer ces informations vers dautres programmes qui les manipuleront intelligemment. De mme, il devrait tre facile de dvelopper, de modifier et de mettre au point vos propres programmes. Et, bien sr, il devrait tre facile de compiler et de lancer ces programmes, de les porter facilement, ceci sur nimporte quel systme dexploitation moderne. Perl fait tout cela, et plus encore. Au dpart conu comme un langage pour administrer UNIX, Perl a t port sur la plupart des systmes dexploitation. De fait, Perl est lun des environnements de programmation les plus portables de nos jours. Pour rendre un programme C ou C++ portable, il faut y inclure ces tranges balises #ifdef diffrentes pour chaque systme cible. Pour rendre un programme Java portable, il est ncessaire de comprendre toutes les particularits de chaque nouvelle implmentation de Java. Pour porter un script shell il est n-

customer_8566

xiv

Prface

cessaire de se souvenir de la syntaxe pour chaque version du systme cible, et ceci pour chaque commande, et donc de trouver le plus petit dnominateur commun, qui avec un peu de chances fonctionnera partout. Pour porter un programme crit en Visual Basic, il faudra alors une dfinition plus souple du mot portable. :-) Perl, par on ne sait quelle magie, vite de tels problmes en retenant les cts positifs de ces langages. Cette magie a plusieurs sources : lutilit de ces mthodes, la crative communaut Perl et la f loraison du logiciel libre. Mais surtout, cette magie vient de son caractre hybride : Perl est un langage mtiss et a toujours vu cette diversit non comme une faiblesse mais comme une force. Alors, si vous avez envie de goter la libert, Perl est fait pour vous. Perl na pas de frontires. lorigine de lexplosion du langage Perl, il y a le dsir des premiers programmeurs systme Unix de ne garder que le meilleur de cet ancien monde . Pour ceux-ci, Perl est une distillation portable de la culture Unix, et une oasis dans un dsert sans issues. Ce qui est satisfaisant, cest que lon peut tout aussi bien retraverser de lautre ct : les designers de sites web sont heureux de pouvoir faire fonctionner leurs scripts Perl sans modification sur le serveur de leur socit. La raison pour laquelle Perl est si populaire parmi les programmeurs systme et les dveloppeurs de sites web, cest tout simplement parce quils lont dcouvert en premier ; mais Perl aspire une plus large audience. Depuis ses dbuts, comme simple langage traducteur dautres langages, Perl sest dvelopp comme un langage sophistiqu est trs gnral, accompagn dun systme de dveloppement complet avec dbogueur, optimiseur, rfrenceur crois, compilateur, diteur orient syntaxe et toute une bibliothque de modules en faisant ainsi un vritable langage de programmation. Mais ce qui diffrencie vraiment Perl, cest quil a toujours su garder une vision simple des choses qui lintressent. Sa puissance et son accessibilit le rendent utilisable dans tous les domaines de la connaissance, de lingnierie spatiale la biologie molculaire, des mathmatiques la linguistique, du graphisme au traitement des documents, de la gestion des bases de donnes celle des rseaux. Perl est utilis pour traiter rapidement une grande quantit dinformations, aussi bien des squences ADN que des pages web. Aussi, lune des plaisanteries de la communaut Perl, est que le prochain crack boursier sera probablement dclench par un bogue dans un script Perl. (Lavantage est que les analystes boursiers au chmage pourront toujours se reconvertir.) Il existe de nombreuses raisons au succs de Perl. Le langage Perl fut lun des premiers projets de la communaut du logiciel libre. Perl est libre et le sera toujours. Grce sa licence trs ouverte, vous pouvez lutiliser o bon vous semble : au travail ou dans des applications commerciales, sans restriction et sans redevance. Et sil survient une difficult que la communaut Perl ne peut rsoudre, vous disposez en dernier recours du code source. Elle nest pas du genre vous faire payer des mises jour. Elle ne mettra pas la cl sous la porte en laissant votre programme orphelin. Que Perl soit un langage libre la srement beaucoup aid. Mais cest aussi le cas de la plupart des logiciels libres qui prosprent. Perl autorise tous ces degrs de libert car cest un langage dont la personnalit est clate. Il sagit dun langage la fois trs simple et trs riche. Il a pris de bonnes ides presque partout, et les a implantes dans un cadre facile utiliser. Pour ceux qui laiment sans plus, Perl est le Practical Extraction and Report Language. Pour ceux qui ne jurent que par lui, Perl est le Pathologically Eclectic Rubbish

customer_8566

Prface

xv

Lister. Pour les minimalistes du lot, Perl ressemble une dmonstration de redondance inepte. Pas de problme. Le monde a besoin de quelques rductionnistes (surtout chez les physiciens). Les rductionnistes aiment isoler les choses. Nous, nous essayons de leur donner un sens. Perl est par bien des aspects un langage simple. Point nest besoin de connatre de nombreuses incantations mystrieuses pour compiler un programme Perl ; il suffit de lexcuter comme un script shell. Les types et les structures employs par Perl sont faciles utiliser et comprendre. Perl nimpose pas de limitation arbitraire vos donnes ; vos chanes et vos tableaux peuvent crotre tant quils veulent (tant quil reste de la mmoire) et ils sont conus pour sadapter leur croissance. Au lieu de vous forcer apprendre de nouvelles syntaxes et de nouveaux concepts, Perl emprunte de nombreuses notions dautres langages qui peuvent vous tre familiers (comme le C, awk, BASIC, Python, langlais et le grec). En fait, pratiquement nimporte quel programmeur peut lire un bout de code Perl bien crit et se faire une ide de son fonctionnement. Le plus important est le fait que vous navez pas besoin de tout connatre de Perl avant de pouvoir crire des programmes utiles. On peut apprendre Perl par le petit bout de la lorgnette . Vous pouvez programmer comme un enfant qui commence parler, nous vous promettons de ne pas rire. De nombreuses ides de Perl sont empruntes au langage naturel, et lune des meilleures est quil ny a aucun problme utiliser un sousensemble du langage tant quon arrive ses fins. Nimporte quel niveau de comptence technique est acceptable dans la culture Perl. Il nexiste pas de police du langage. Un script Perl est correct sil vous aide terminer votre travail avant que le patron ne vous mette dehors. Bien quil soit simple par de nombreux aspects, Perl est galement un langage riche dont il y a beaucoup apprendre. Cest le prix payer pour faciliter ce qui est difficile. Il vous faudra un certain temps pour en assimiler toutes les possibilits, mais vous serez heureux davoir accs ses remarquables capacits quand vous en aurez besoin. Nous avons fait remarquer plus haut que Perl emprunte de nombreuses aptitudes aux shells et au C, mais il possde aussi un sur-ensemble strict de celles de sed et de awk. Il existe en fait des traducteurs fournis avec Perl pour transformer les anciens scripts sed et awk en scripts Perl, et vous pouvez donc voir comment les fonctionnalits avec lesquelles vous pouvez dj tre familiers correspondent celles de Perl. En raison de cet hritage, Perl tait dj riche alors mme quil ntait quun langage de rduction de donnes, conu pour naviguer dans des fichiers, scruter de grandes quantits de texte, crer et obtenir de donnes dynamiques et afficher des rapports facilement formats se basant sur ces donnes. Mais un moment donn, Perl a commenc spanouir. Il est alors devenu un langage de manipulation de systmes de fichiers, de gestion de processus, dadministration de bases de donnes, de programmation clientserveur, de programmation scurise, de gestion dinformations bases sur le Web, et mme de programmation oriente objet et fonctionnelle. Ces possibilits nont pas t simplement colles aprs coup ; chacune fonctionne en synergie avec les autres, parce que Perl a t conu ds le dpart comme un langage dintgration. Mais Perl peut intgrer plus que ses propres capacits. Perl est conu pour tre extensible de faon modulaire. Perl vous permet de rapidement concevoir, programmer, mettre au point et dployer des applications, mais il vous permet galement dtendre aisment les fonctionnalits de ces applications quand le besoin sen fait sentir. On peut intgrer Perl dautres langages, et on peut intgrer dautres langages Perl. Le mca-

customer_8566

xvi

Prface

nisme dimportation de modules permet dutiliser ces dfinitions externes comme sil sagissait de fonctionnalits propres Perl. Les bibliothques orientes objet conservent cette proprit. Perl vous assiste en bien dautres manires. Perl compile dabord votre programme dans un code intermdiaire, alors quun langage interprt classique compile et excute une commande la fois. Il effectue diverses optimisations comme tout autre compilateur et donne des rsultats instantans concernant entre autres les erreurs de syntaxe et les problmes de liaison avec les bibliothques. Une fois que la partie en amont a valid le programme, elle passe le code intermdiaire linterprteur en aval qui lexcute (ou, si lon prfre, une autre routine de traitement capable dmettre du code C ou du langage machine). Tout ceci peut paratre compliqu, mais le compilateur et linterprteur sont assez efficaces, et la plupart dentre nous comptent le cycle compiler-lancer-dboguer en secondes. Ce cycle rapide associ une gestion douce des erreurs fait de Perl un langage idal pour le prototypage. Au fur et mesure que le programme se dveloppe, on peut resserrer les boulons et programmer avec moins de f lair mais plus de discipline. Perl vous y aide galement, quand vous le lui demandez gentiment. Perl vous permet aussi dcrire des programmes plus srs. En plus des interfaces de scurit implmentes par les autres langages, un mcanisme de traage automatique des source dinscurit, bloque toute opration dangereuse. Enfin, Perl permet de dfinir des compartiments spcialement protgs dans lesquels on peut excuter en toute scurit du code Perl dorigine douteuse, en masquant les oprations dangereuses. Mais, paradoxalement, la meilleure aide que Perl puisse vous apporter na presque rien voir avec Perl, mais tout voir avec les gens qui lutilisent. Les Perlistes comptent parmi les gens les plus utiles sur terre, vraiment. Sil existe un aspect religieux au mouvement Perl, cest celui-l. Larry a voulu que la communaut Perl fonctionne comme un bout de paradis, et il semble que son souhait se soit ralis jusqu prsent. Puissiez-vous faire de votre mieux pour que cela continue. Que vous appreniez Perl parce que vous voulez sauver le monde, ou simplement parce que vous tes curieux, ou encore parce que votre patron vous a dit de vous y mettre, ce livre vous mnera de ses bases les plus lmentaires vers ses labyrinthes les plus obscurs. Et mme si nous navons pas lintention de vous apprendre programmer, le lecteur attentif en retirera un peu de lart, et de la science, de la programmation. Nous vous encouragerons dvelopper les trois grandes vertus du programmeur : la paresse, limpatience et lorgueil. Tout au long de ce parcours, nous esprons que vous trouverez ce livre assez amusant par certains cts (et dun humour ravageur par dautres). Et si rien de tout cela ne vous suffit, souvenez-vous que lapprentissage de Perl enrichira votre curriculum vitae. Continuez donc votre lecture.

Ce qui est nouveau dans cette dition


Presque tout... Sauf des morceaux choisis de la prcdente dition (et ils taient nombreux), nous avons entirement rvis la prsente dition pour plusieurs raisons. Premirement nous avons voulu rendre le livre accessible un plus large public. Il y a trs peu de prrequis. Nous avons volontairement choisi un style vivant pour garder veills ceux qui en auraient beaucoup (des prrequis).

customer_8566

Prface

xvii

Deuximement, nous avons prsent les derniers dveloppements de Perl. Mme si ceux-ci restent ltat dexprience de laboratoire, le noyau central est solidement plant. La foule adopter pour suivre le dveloppement de certaines extensions, peut tre torride. Cest pourquoi nous vous indiquerons daller voir plutt la documentation en ligne, pour prciser certains aspects, car Perl est un langage de mcanicien et on peut confondre un boulon de 8 avec un boulon de 10. Enfin, nous avons adapt cette dition pour en faciliter la lecture, en sparant les chapitres en parties introduisant chacune un concept, dans le but de mieux saisir lensemble. Cette nouvelle dition sorganise ainsi : Partie I, Survol de Perl Le dmarrage est toujours difficile. Cette partie prsente les ides fondamentales du langage sur un ton informel et est lire au coin du feu. Il sagit plus dun marchepied que dun didacticiel complet, et elle peut ne pas correspondre aux besoins de tout le monde. Voir la section Documentation papier pour les livres qui pourraient mieux convenir. Partie II, Sance de dissection Cette partie est un dveloppement btons rompus et en profondeur des mcanismes essentiels du langage chaque niveau dabstraction, depuis les types de donnes, les variables, les expressions rgulires jusquaux routines, modules et objets. Vous y acquerrez une bonne mesure du fonctionnement de ce langage ainsi que quelques bonnes mthodes de conception de logiciels. (Et si vous navez jamais utilis un langage permettant la reconnaissance des modles, vous allez avoir un traitement de faveur.) Partie III, Technique Perl Il est possible de faire beaucoup de choses avec Perl et ce chapitre vous emmnera beaucoup plus loin. Ici, vous apprendrez comment rpondre tous les dfis lancs par votre machine, depuis le traitement des caractres Unicode, la communication entre processus, le multithreading, la compilation, le dbogage et loptimisation de Perl, jusqu lcriture de vos propres extensions en C ou C++ ou linterfaage de toute API. Perl est tout fait adapt pour communiquer avec votre PC, et si besoin avec les autres PC sur Internet. Partie IV, Culture Perl Toute culture ayant un langage, la communaut Perl a vite compris quelle devait se forger une culture. Nous verrons dans cette partie la programmation Perl dans la vie de tous les jours. Nous verrons comment reconnatre les bons des mchants, et aussi comment nous amliorer pour produire des programmes rutilisables par tout le monde. Partie V, Rfrences Nous avons regroup dans cette partie tous les termes importants de chaque chapitre, depuis les variables et fonctions spciales, aux modules et pragmas standards. Le glossaire sera particulirement utile ceux qui ne sont pas familiers avec le jargon informatique. Par exemple, si vous ignorez le sens du terme pragma , vous pouvez le dcouvrir ds maintenant.

customer_8566

xviii

Prface

Distribution standard
Aujourdhui, la grande majorit des systmes dexploitation comprennent une distribution de Perl en standard. Au moment o ces lignes sont crites, les systmes AIX, BeOS, BSDI, Debian, DG/X, DYNIX/ptx, FreeBSD, IRIX, LynxOS, Mac OS X, OpenBSD, RedHat, SINIX, Slackware, Solaris, SuSE, Mandrake et Tru64, sont tous distribus avec une version de Perl en standard. Certaines socits fournissent Perl sur un CD de distribution libre ou bien par lintermdiaire de leur service client. Des socits tierces comme ActiveState, proposent des distributions pour diffrents systmes y compris Microsoft. Mme si votre distributeur livre Perl en standard, vous aurez probablement envie de compiler et dinstaller Perl vous-mme. Vous serez ainsi certain davoir la dernire version, et de pouvoir installer o bon vous semble la documentation ainsi que les bibliothques. Vous pourrez aussi choisir parmi les diffrentes options de compilation tels que le multithreading, la gestion des grands fichiers, ou bien les options de dbogage de bas niveau disponible par le slecteur -D. (Le dbogage niveau utilisateur est toujours support.) La faon la plus simple dobtenir les sources de Perl est daller www.perl.com, o vous trouverez les informations les plus importantes, ainsi que des liens vers des distributions binaires spcifiques aux plates-formes sans compilateurs C. Vous pouvez aussi vous rendre directement sur le CPAN (Comprehensive Perl Archive Network, dcrit au chapitre 22, CPAN, ladresse http://www.Perl.com/CPAN ou bien http://www.cpan.org. Si ces adresses sont trop lentes (cest possible car elles sont trs populaires), vous pouvez choisir ainsi un miroir plus proche de chez vous. Les adresses url suivantes ont t choisies parmi les centaines de miroirs CPAN dans le monde : http://www.funet.fi/pub/languages/Perl/CPAN/ ftp://ftp.funet.fi/pub/languages/Perl/CPAN/ ftp://ftp.cs.colorado.edu/pub/Perl/CPAN/ ftp://ftp.cise.ufl.edu/pub/Perl/CPAN/ ftp://ftp.Perl.org/pub/Perl/CPAN/ http://www.Perl.com/CPAN-local http://www.cpan.org/ http://www.Perl.org/CPAN/ http://www.cs.uu.nl/mirror/CPAN/ http://CPAN.pacific.net.hk/ Les deux premires de la liste, sur le site funet.fi, pointent sur le rpertoire matre de tous les sites CPAN. Le fichier MIRRORED.BY contient la liste de tous les sites pour laisser le choix du site miroir ainsi que du protocole pour le tlchargement (FTP ou HTTP), ce qui est utile lorsque votre rseau est derrire un firewall. Le site multiplexeur http://www.Perl.com/CPAN vous aide faire cette slection. Une fois que vous avez rcupr et dcompact le code source dans un rpertoire, vous devez lire les fichiers README et INSTALL pour comprendre comment construire lexcutable Perl. Il peut aussi y avoir un fichier INSTALL.platform o platform dsigne votre plate-forme systme.

customer_8566

Prface

xix

Si votre platform est un systme Unix ou similaire, alors les commandes pour charger, configurer, construire et installer Perl seront celles qui suivent. Premirement vous devez utiliser une commande pour charger le code source. Avec ftp :
% ftp ftp://ftp.funet.fi/pub/languages/Perl/CPAN/src/latest.tar.gz

(vous pouvez substituer un miroir CPAN plus proche. Si vous habitez en Finlande cest votre miroir CPAN le plus proche.) Si vous ne pouvez utiliser ftp, alors tlcharger sur le Web avec un navigateur ou bien la ligne de commande suivante :
% wget http://www.funet.fi/pub/languages/Perl/CPAN/src/latest.tar.gz

Ensuite, il faut dcompacter, configurer, construire et installer :


% % % % tar zxf latest.tar.gz cd Perl-5.6.0 sh Configure -des make test && make install ou gunzip, et ensuite tar xf. ou 5.* pour toute version. Rponses par dfaut. En mode super-utilisateur.

Ces commandes seffectuent dans un environnement de dveloppement C conventionnel, et ncessitent donc un compilateur C. Pour connatre les diffrentes mises jour et versions de Perl pour chaque plate-forme, si vous avez besoin dune version standard ou dun portage spcial, explorez le rpertoire CPAN ports. Des liens sont disponibles pour tlcharger ses portages spciaux ou pour les systmes ne disposant pas de compilateurs C.

Documentation en ligne
Limportante documentation en ligne de Perl fait partie de la distribution standard. (Voir la section suivante pour la documentation papier.) Chaque module CPAN est accompagn de sa documentation. Quand nous faisons rfrence au manuel Perl , nous parlons de lensemble des pages en ligne du manuel Perl, sur votre PC. Le terme manuel est purement une convention indiquant un fichier contenant de la documentation (nul besoin dun programme man pour la lire. Elles peuvent mme tre au format HTML sur les systmes diffrents dUnix. Le manuel Perl en ligne a t divis en diffrentes sections, pour pouvoir facilement trouver ce que lon cherche sans avoir parcourir des centaines de pages de texte. Le manuel Perl de base se nomme perl, et on y accde avec la commande man perl1. Ce manuel vous orientera vers dautres plus spcifiques. Par exemple man perlre affichera le manuel des expressions rgulires de Perl. La commande perldoc fonctionne souvent sur les systmes ou la commande man ne fonctionne pas. Sur Mac, il faut utiliser le programme Shuck. Votre distribution peut aussi fournir le manuel Perl au format HTML, ou bien le format daide natif du systme hte.

1. Si vous obtenez une page illisible cest probablement que votre version de manuel est trop ancienne. Vrifiez votre variable denvironnement MANPATH. (Essayez la commande perldoc perl pour configurer MANPATH sur la valeur retourne par la commande perl -V:man.dir.)

customer_8566

xx

Prface

Consultation du manuel standard


lorigine du langage, en 1987, le manuel perl tait un document concis denviron vingt-quatre pages dactylographies. La section concernant les expressions rgulires noccupait que deux paragraphes. (avec la connaissance de la commande egrep cela pouvait suffire.) Dune certaine faon tout a chang depuis : de la documentation standard, les diffrents utilitaires, linformation pour le portage entre les diffrentes plates-formes et les centaines de modules standard, il y a maintenant plus de 1500 pages dactylographis de documentation rparties entre plusieurs manuels. (Sans compter les modules CPAN que vous installerez.) Dun autre ct rien na chang : le manuel de base perl existe toujours, et cest toujours le point de dpart si vous tes perdu. La diffrence est que lorsque vous y tes, vous ne pouvez vous y arrter. La documentation Perl nest plus une petite picerie mais un grand centre commercial avec des centaines de magasins o il est ncessaire de savoir o lon est pour savoir o lon va. Une fois que lon connat le plan, il est facile de sorienter. Voici quelques points de repre que vous pourrez rencontrer le :
Manuel perl perldata perlsyn perlop perlre perlvar perlsub perlfunc perlmod perlref perlobj perlipc perlrun perldebug perldiag Sujet Les diffrents manuels Perl disponibles. Les types de donnes. La syntaxe Perl. Prcdence des oprateurs. Les expressions rgulires. Les variables prdfinies. Les routines Perl. Les fonctions prdfinies. Mise en uvre des modules. Les rfrences. Les objets. La communication interprocessus. Lutilisation des commandes Perl avec slecteurs. Le dbogage. Les messages de diagnostic.

Cest juste un aperu, mais ce sont les entres essentielles : si vous voulez connatre un oprateur, perlop vous donnera la rponse, et vous cherchez une chose sur les variables prdfinies, regardez dans perlvar. Pour comprendre un message derreur, allez dans perldiag. Et ainsi de suite. Les FAQ (questions revenant frquemment) sont une partie standard du manuel Perl. Elles sont divises en neuf manuels diffrents :

customer_8566

Prface
Manuel perlfaq1 perlfaq2 perlfaq3 perlfaq4 perlfaq5 perlfaq6 perlfaq7 perlfaq8 perlfaq9 Sujet Les questions gnrales sur Perl. La rcupration et lapprentissage de Perl. Les outils de programmation. Les manipulation des donnes. Les fichiers et formats. Les expressions rgulires. Les questions dordre gnral sur le langage. Linteraction avec le systme. La connexion au rseau.

xxi

Certains manuels rassemblent des notes spcifiques certaines plates-formes :


Manuel perlamiga perlcygwin perldos perlhpux perlmachten perlos2 perlos390 perlvms perlwin32 Sujet Le portage sur Amiga. Le portage sur Cygwin. Le portage sur MS DOS. Le portage HP UX. Le portage sur Power MachTen. Le portage sur OS/2. Le portage sur OS/390. Le portage sur DEC VMS. Le portage sur MS-Windows.

(Voir aussi le chapitre 25, Portabilit, et le rpertoire des portages du CPAN dj dcrit pour toute information relative ce sujet.)

Recherche dans le manuel


Nessayez pas de lire les 1500 pages du manuel, autant chercher une aiguille dans une botte de foin. Il y a un vieux dicton qui dit quon ne peut pas grapper des arbres morts.2 Chacun des manuels Perl, dispose de son propre outil de recherche et de visualisation. Il est possible de chercher une page du manuel en indiquant la commande constitue du nom du manuel suivi dune expression rgulire comme paramtre (voir le chapitre 5, Recherche de motif) :
% % % % perlop comma perlfunc split perlvar ARGV perldiag assigned to typeglob

2. Noubliez pas le glossaire.

customer_8566

xxii

Prface

Il est possible dtendre la recherche sur un manuel entier, par exemple pour chercher dans les FAQ, utilisez la commande perlfaq (qui est aussi un manuel) :
% Perlfaq round

La commande perltoc (aussi un manuel) cherche dans le sommaire gnral de tous les manuels :
% perltoc typeglob Perl5005delta: Undefined value assigned to typeglob Perldata: Typeglobs and Filehandles Perldiag: Undefined value assigned to typeglob

Ou alors, pour trouver une chane dans toutes les ressources en ligne du manuel, incluant les en-ttes, les descriptions et exemples, utilisez la commande perlhelp :
% perlhelp CORE::GLOBAL

Voir le manuel perldoc pour les dtails.

Les autres manuels


Quand nous parlons de documentation non-Perl, comme par exemple dans getitimer(2), nous faisons rfrence aux manuels getitimer dans la section 2 du manuel Unix Programmers Manual.3 Les pages du manuel pour les appels systme tel getitimer peuvent ne pas tre prsentes sur les systmes non Unix, mais ce nest pas grave car vous ne pouvez pas les utiliser dans ce cas. Si vous en avez vraiment besoin, vous les trouverez facilement publis sur le Web une recherche rapide de "+crypt(3) +manual" avec AltaVista vous permettra den obtenir plusieurs versions. Mme si les principaux manuels Perl sont installs dans la section 1 du rpertoire standard de man, nous omettrons lindice (1) quand nous y ferons rfrence dans ce livre. Vous les reconnatrez nanmoins sans difficult car ils sont tous de la forme perlmumble .

Documentation papier
Voici quelques titres de la littrature Perl que nous vous recommandons de : Perl 5 Prcis et concis, 2e ed., de Johan Vromans (OReilly, 2000). Ce manuel au format poche est une rfrence pratique et rapide. Perl en action, par Tom Christiansen et Nathan Torkington (OReilly, 1998). Un livre pour accompagner celui-ci. Elements of Programming with Perl, Andrew L. Johnson (Manning, 1999). Pour commencer partir de 0 en utilisant Perl, pour les non programmeurs.

3. La section 2 contient les appels directs des fonctions du systme. (et sont appeles appels systmes , ne pas confondre avec les appels la fonction system, ce qui na rien voir. Cependant, les systmes diffrent quant limplmentation de ces appels systmes entre ceux qui utilisent la fonction system et ceux qui font appel aux fonctions de la bibliothque C, ce qui fait que lon peut trouver getitimer(2) dans la section 3 (Sous Programmes) au lieu de la section 2 (Appels Systmes).

customer_8566

Prface

xxiii

Introduction Perl, 2e ed., par Randal Schwartz et Tom Christiansen (OReilly, 1997). Pour les administrateurs et programmeurs du systme Unix : lutilisation de 30 % du langage dans 70 % des cas. La version sur le systme Microsoft revue par Erik Olson sappelle LearningPerl for Win32 Systems. Perl: The Programmers Companion, par Nigel Chapman (Wiley, 1997). Ce livre trs concis est destin aux ingnieurs et programmeurs en informatique et considre Perl indpendamment de la plate-forme, dune manire complte. Matrise des expressions rgulires, par Jeffrey Friedl (OReilly, 1997). Bien quil ninclut pas les derniers ajouts sur les expressions rgulires, il reste une rfrence indispensable pour quiconque cherche mieux comprendre comment celles-ci fonctionnent. Object Oriented Perl, par Damian Conway (Manning, 1999). Pour les dbutants aussi bien que les programmeurs objet avancs, ce livre tonnant dveloppe des techniques simples et exotiques dans le but dcrire des systmes objets puissants en Perl. Mastering Algorithms with Perl, par Jon Orwant, Jarkko Hietaniemi et John Macdonald (OReilly, 1999). Toutes les techniques utiles dun cours sur les algorithmes, sans les preuves ardues. Ce livre couvre les algorithmes fondamentaux dans le domaine des graphes, du traitement de texte, des ensembles et plein de bonnes choses encore. Writing Apache Modules with Perl and C, par Lincoln Stein et Doug MacEachern (OReilly, 1999). Ce guide de la programmation web enseigne comment tendre les capacits du serveur Apache en utilisant le module turbo mod_Perl pour lexcution rapide des scripts CGI ainsi que l API de ce serveur accessible Perl. The Perl Journal, dit par Jon Orwant. Ce magazine trimestriel cr par des programmeurs pour des programmeurs, dtaille des trucs et astuces, parle des dernires nouvelles et de plein dautres choses encore.

Il existe une plthore de livres et de publications sur le sujet et nous avons srement oubli des rfrences (nous avons nglig sans piti les mauvaises). En plus de ceux que nous venons de citer, nous vous recommandons les livres suivants. Ils nont pas un rapport direct avec le langage mais sont trs pratiques comme rfrence, pour la consultation et linspiration. The Art of Computer Programming, par Donald Knuth, vol. 1, Fundamental Algorithms ; vol. 2, Seminumerical Algorithms ; et vol. 3, Sorting and Searching (Addison-Wesley, 1998). Introduction to Algorithms, par Cormen, Leiserson et Rivest (MIT Press and McGrawHill, 1990). Algorithms in C: Fundamental Data Structures, Sorting, Searching, 3e ed., par Robert Sedgewick (Addison-Wesley, 1997). The Elements of Programming Style, par Kernighan et Plauger (Prentice-Hall, 1988). The Unix Programming Environment, par Kernighan et Pike (Prentice-Hall, 1984). POSIX Programmers Guide, par Donald Lewine (OReilly, 1991). Advanced Programming in the UNIX Environment, par W. Richard Stevens (AddisonWesley, 1992).

customer_8566

xxiv

Prface

TCP/IP Illustrated, vols. 13, par W. Richard Stevens, (Addison-Wesley, 19941996). Le seigneur des anneaux de J. R. R. Tolkien

Ressources supplmentaires
LInternet est une merveilleuse invention et nous dcouvrons tous les jours comment utiliser tout son potentiel. (Certains prfreront dcouvrir lInternet la manire dont Tolkien dcouvre la Terre du Milieu. )

Perl sur le web


Allez voir la page daccueil de Perl ladresse http://www.Perl.com/. On y parle des nouveauts dans le monde Perl, vous y trouvez du code source et diffrents reportages, des articles thmatiques, de la documentation, les dates des confrences et bien dautres choses encore. Allez aussi voir la page des Mongueurs ladresse http://www.Perl.org et vous pourrez constater que Perl est comme une herbe sauvage qui pousse partout dans le monde sauf au ple sud. Des groupes locaux de mongueurs se runissent rgulirement avec lesquels vous pouvez changer vos points de vue entre hackers.

Groupe de news Usenet


Les groupes de news Perl sont une source dinformations remarquable, bien que parfois confus. comp.lang.Perl.announce est un groupe modr dun faible trafic sur les annonces concernant Perl. Il sagit frquemment de nouvelles versions, de corrections de bogues, de nouvelles extensions et de nouveaux modules et de FAQ (Frequently Asked Questions, questions frquemment poses4). Le groupe comp.lang.Perl.misc traite aussi bien des problmes techniques que de la philosophie de Perl, des jeux en Perl et de la posie en Perl. Tout comme Perl lui-mme, comp.lang.Perl.misc se veut utile, et aucune question nest trop stupide.5 Le groupe comp.lang.Perl.tk discute de lutilisation du fameux module Perl/Tk. Le groupe comp.lang.Perl.modules concerne le dveloppement et lutilisation des modules Perl qui sont le meilleur moyen pour rutiliser le code. Il y a dautres groupes du type comp.lang.Perl.un_groupe qui nexistent pas au moment o nous crivons ces lignes, alors nhsitez pas naviguer. Si vous nutilisez pas un lecteur de news classique pour accder Usenet, mais plutt un navigateur web, placez devant le nom du groupe len-tte "news:" pour accder lun de ceux que vous cherchez. (Cela fonctionne seulement si vous avez un serveur de news) Vous pouvez aussi les chercher laide de AltaVista ou Deja en prcisant *Perl* comme nom du groupe dutilisateurs. Un dernier groupe dutilisateurs quil vous sera utile de consulter, au moins si vous tes
4. Ou Foire Aux Questions. 5. Il est vident que certaines questions sont trop stupides... surtout celles dont la rponse se trouve dans la FAQ.

customer_8566

Prface

xxv

programmeur CGI, est le groupe comp.infosystems.www.authoring.cgi. Mme si ce nest pas strictement parler un groupe dutilisateurs Perl, la plupart des programmes dexemples sont crits en Perl, moins que vous nutilisez le module Apache mod_Perl, auquel cas vous pouvez consulter comp.infosystems.www.servers.unix.

Rapports de bogues
Au cas improbable o vous trouviez un bogue propre Perl et non votre programme, essayez de le rduire un cas de test minimal avant de le rapporter via le programme Perlbug qui est fourni avec Perl. Voir le lien http://bugs.Perl.org pour plus dinformations.

De laide en franais
Si vous voulez en savoir plus sur Perl dans un cadre sympathique, il existe des groupes dutilisateurs francophones de Perl. Voici dailleurs un message du fondateur dun de ces groupes :
Jespre que ce livre apportera satisfaction aux lecteurs francophones qui dsirent (mieux) programmer en Perl. Ce nest pas toujours possible pour quelquun dont langlais nest pas la langue maternelle de comprendre toutes les subtilits des points techniques, ainsi que les plaisanteries et les jeux de mots qui sont lgion dans la documentation anglaise. Je crois savoir, pour avoir cout (et parfois rpondu) leurs questions, que les traducteurs de cet ouvrage nont pas failli sur les explications des subtilits techniques et aussi ont-ils fait de leur mieux pour traduire les plaisanteries. Toujours est-il que parfois, mme en lisant ce livre de manire assidue, on narrive pas comprendre comment faire marcher un module de CPAN, sil existe un module CPAN qui fait ce que lon souhaite faire, ou sil existe de meilleurs moyens pour effectuer une opration. ce moment-l, on a envie de discuter avec dautres personnes. Par la plus forte concidence, il existe des groupes dutilisateurs de Perl. J'ai fond le premier groupe franais il y a environ trois ans, Paris. Ce sont des mongers, quon pourrait traduire par marchands ; mais que je prfre crire mongueurs (mongueuses au fminin), pour rester plus fidle la prononciation anglaise. Nous avons un site web, ainsi quune liste de diffusion qui, en octobre 2001, compte environ 150 abonn(e)s. Nous avons galement fond une association, dont le but est de promouvoir lutilisation de Perl en France, en soutenant la cration de nouveaux groupes dutilisateurs ( ce jour, Toulouse et Marseille nous ont rejoint) et en organisant des confrences ou des cours consacrs Perl. Cest pourquoi je vous invite venir nous rencontrer, sur notre site web (http://www.mongueurs.net/), notre liste ou nos runions (rendez visite au groupe local prs de chez vous ou mieux, fondez-en un !), pour dcouvrir le ct humain qui se cache derrire le langage qui nous a tant apport et qui continue nous fasciner. David Landgren Prsident de lassociation Les Mongueurs de Perl Octobre 2001

customer_8566

xxvi

Prface

Conventions typographiques
Nous avons consacr une section propre pour dcrire certaines conventions telles les conventions de codage dcrites dans Programmation style au chapitre 24, Techniques couramment employes. Les conventions lexicales sont indiques dans le glossaire (notre lexique). Dans cette dition nous avons utilis les conventions typographiques suivantes : Italique Elle est utilise pour les URL, manuels, noms de fichier et programmes. Les termes nouveaux sont en italique la premire fois quils apparaissent dans le texte. La plupart sont repris plus prcisment dans le glossaire. Chasse constante Elle est utilise dans les exemples et pour indiquer du code insr dans du texte normal. Les valeurs sont crites en chasse constante entre guillemets ( ), qui bien sr ne font pas partie de la valeur. Chasse constante en gras Elle est utilise pour les options de commande, ce qui permet de distinguer entre loption avertissement -w et loprateur -w pour le test dun fichier. Elle est aussi utilise pour le texte que vous entrez littralement. Chasse constante en italique Elle est utilise pour des termes gnriques auxquels vous devez substituer vos valeurs personnelles. Nous listons beaucoup dexemples qui sont pour la plupart des bouts de code qui peuvent sintgrer dans une application plus large. Certains exemples sont des programmes complets et que vous pouvez reconnatre avec len-tte de dbut de ligne #!. Les programmes les plus importants commencent par :
#!/usr/bin/Perl

Dautres programmes doivent aussi tre entrs en ligne de commande. Nous avons utilis le symbole % pour indiquer un prompteur shell :
% Perl -e print "Hello, world.\n" Hello, world.

Ce style reprsentatif dune ligne de commande Unix o les simples guillemets reprsentent la forme la plus quote . La quotation, ainsi que les caractres gnraux (wildcards), varient dun systme lautre. Par exemple beaucoup dinterprteurs de ligne de commande sous MS DOS et VMS ncessitent la double quotation en lieu et place des simples guillemets lorsquil est ncessaire de grouper les arguments avec des espaces ou des caractres gnraux de remplacement.

Remerciements
Nous voulons remercier ici publiquement nos relecteurs pour leur patience dans ldition de cet ouvrage : Todd Miller, Sharon Hopkins Rauenzahn, Rich Rauenzahn, Paul

customer_8566

Prface

xxvii

Marquess, Paul Grassie, Nathan Torkington, Johan Vromans, Jeff Haemer, Gurusamy Sarathy, Gloria Wall, Dan Sugalski et Abigail. Nous voulons remercier tout particulirement Tim OReilly (et ses associs) dencourager les auteurs faire un effort spcial pour rendre leurs livres agrables lire.

Vos apprciations
Nous avons test et vrifi toutes les informations de ce livre du mieux que nous lavons pu, mais vous pouvez dcouvrir que certaines caractristiques ont chang (ou mme que nous avons fait des erreurs). Faites-nous part de toutes les erreurs que vous avez pu rencontrer, de mme que vos suggestions pour les ditions venir, en crivant : OReilly France 18, rue Sguier 75006 Paris Vous pouvez galement nous envoyer des messages lectroniques. Pour vous inscrire sur la liste de diffusion ou demander un catalogue, envoyez un e-mail : info@editions-oreilly.fr Nous avons un site web pour le livre o nous listons toute erreur et information relative la srie des chameaux : http://www.oreilly.fr/catalogue/pperl3.html Vous y trouverez galement le code source des exemples de ce livre.

customer_8566

customer_8566

Survol de Perl

customer_8566

customer_8566

Vue densemble

Dmarrage
Nous pensons que Perl est un langage facile apprendre et utiliser, et nous esprons vous en convaincre. Lun des aspects les plus agrables de Perl est que lon na pas besoin den crire beaucoup avant dexprimer vraiment sa pense. Dans de nombreux langages de programmation, il faut dclarer les types, les variables et les sous-programmes que lon va utiliser avant dcrire la premire instruction de code excutable. Cest une bonne approche pour des problmes complexes demandant des structures de donnes complexes ; mais pour pour beaucoup de problmes simples, que lon rencontre tous les jours, il vaut mieux un langage de programmation dans lequel il suffit dcrire :
print "Salut tout le monde!\n";

et o le programme ne fait que cela. Perl est de ce genre de langage. En fait, cet exemple est un programme complet, et si on le donne linterprteur Perl, il affiche Salut tout le monde ! lcran.1 (Le caractre \n produit un saut de ligne en sortie.) Et voil. Il ny a pas non plus grand-chose crire aprs ce que lon veut dire, dailleurs. linverse de nombreux langages, Perl estime que sarrter sans prvenir la fin du programme nest quune faon normale den sortir. On peut bien sr appeler explicitement la fonction exit si on le souhaite, de mme que lon peut dclarer certaines variables ou certains sous-programmes, ou mme se forcer dclarer toutes les variables et tous les sous-programmes. vous de voir. En Perl, vous tes libre de faire Ce Quil Faut, quelle quen soit votre dfinition. Il existe dautres raisons la facilit demploi de Perl, mais il serait inutile de toutes les numrer ici... car cest lobjet de ce livre. Le diable est dans les dtails, comme disent les Anglo-saxons, mais Perl essaie aussi de vous sortir de lenfer o vous pouvez vous retrouver plong. Cest tous les niveaux que Perl essaye de vous faire arriver vos fins avec
1. Ou un script, ou une application, ou un excutable, ou un machin. Ce quon veut.

customer_8566

Chapitre 1 Vue densemble

le minimum dennuis et le maximum de plaisir. Cest pourquoi tant de programmeurs Perl affichent un sourire bat. Ce chapitre constitue un survol de Perl, et nous nessayons pas de le prsenter la partie rationnelle de votre cerveau. Nous nessayons pas plus dtre complets ou logiques. Ce sera lobjet du prochain chapitre. Les Vulcains, les androdes ainsi que les humains de cette espce, peuvent aller directement au chapitre 29, Fonctions, pour avoir toute linformation. Ce livre prsente Perl lautre partie de votre cerveau, que vous lappeliez associative, artistique, passionne, ou simplement spongieuse. Dans ce but, nous prsenterons divers aspects de Perl qui vous en donneront une image aussi claire que celle dun lphant pour un aveugle. Allons, nous allons essayer de faire mieux. Il sagit ici dun chameau, aprs tout. Esprons quau moins un de ces aspects du langage vous mettra en selle.

Langages naturels et artificiels


Les langages ont dabord t invents par les humains, pour les humains. Ce fait a parfois t oubli dans les annales de linformatique.2 Perl ayant t conu (pour ainsi dire) par un linguiste occasionnel, il a t invent pour fonctionner aussi aisment que le langage naturel. Cela recouvre plusieurs notions, puisque le langage naturel fonctionne simultanment plusieurs niveaux. Nous pourrions numrer ici nombre de ces principes linguistiques, mais le plus important est que les choses simples doivent le rester et que les choses complexes ne doivent pas tre impossibles. Cela peut sembler vident, mais de nombreux langages informatiques ne remplissent pas ces deux conditions. Les langages naturels permettent les deux parce que les gens essayent continuellement dexprimer des choses simples et des choses complexes, ce qui fait que le langage volue pour grer les deux. Perl a t conu avant tout pour voluer, et cest ce qui sest produit. De nombreuses personnes ont contribu lvolution de Perl au cours des ans. Nous plaisantons souvent en disant que le chameau est un cheval conu par un comit, mais si lon y pense, le chameau est parfaitement adapt la vie dans le dsert. Il a volu pour devenir relativement autosuffisant. (En revanche, lvolution de lodeur du chameau est discutable. Cela vaut pour Perl.) Quand quelquun prononce le mot linguistique , on pense en gnral soit des mots, soit des phrases. Mais les mots et les phrases ne sont que deux manires pratiques de morceler la parole. Ils peuvent tous deux tre scinds en units smantiques plus petites, ou combins en units plus grandes. Et la signification de chaque unit dpend largement du contexte syntaxique, smantique et pragmatique dans lequel se trouve lunit. Le langage naturel comporte des mots de diverses sortes, des noms, des verbes, etc. Si je dis pile tout seul, il y a de fortes chances pour que vous pensiez quil sagisse dun nom. Mais je peux lemployer autrement : comme un verbe, comme un adverbe, etc., selon le contexte. Si je pile devant une pile de piles minuit pile, jai intrt disposer dune pile.3

2. Plus prcisment, ce fait a parfois d tre rappel. 3. Vous trouvez sans doute que ces considrations linguistiques manquent de sex-appeal. Le but est simplement de vous montrer en quoi Perl est diffrent dun langage informatique classique.

customer_8566

Langages naturels et artificiels

De mme, Perl value les mots de faon diffrente dans des contextes diffrents. Nous le verrons plus tard. Souvenez-vous que Perl essaie de comprendre ce que vous dites ; il est lcoute. Perl essaie vraiment daller jusquau bout. Dites ce que vous pensez, et en gnral, Perl le saisira ( moins dcrire des choses absurdes, bien sr ; lanalyseur de Perl comprend le Perl bien mieux que le Franais ou le Swahili). Mais revenons aux noms. Un nom peut dsigner un objet prcis, ou il peut nommer une classe dobjets gnrique. La plupart des langages de programmation font cette distinction, sauf que nous appelons valeur une chose prcise et variable une chose gnrique. Une valeur existe quelque part, peu importe o, mais une variable est associe une ou plusieurs valeurs durant son existence. Ce qui interprte la variable doit garder la trace de cette association. Cet interprteur peut se trouver dans votre cerveau, ou dans votre ordinateur.

Syntaxe dune variable


Une variable nest quun endroit pratique pour conserver quelque chose, un endroit qui a un nom, ce qui fait que vous pouvez retrouver vos petits quand vous y revenez plus tard. Tout comme dans la vie relle, il existe de nombreux endroits pour ranger des choses, certains privs et certains publics. Certains lieux sont temporaires et dautres sont permanents. Les informaticiens adorent parler de porte des variables, mais cest peu prs tout ce quils entendent par l. Perl connat de nombreux moyens de traiter les problmes de porte, ce que vous serez ravis dapprendre le moment venu. (Regardez lemploi des adjectifs local, my et our dans le chapitre 29, si vous tes curieux, ou bien regardez Dclarations avec porte dans le chapitre 4, Instructions et dclarations.) Mais on classifie plus efficacement les variables par le type de donnes quelles peuvent reprsenter. De mme quen franais, la premire distinction se fait entre le singulier et le pluriel. Les chanes et les nombres sont des bouts de donnes singulires, alors que les listes de chanes ou de nombres sont plurielles (et quand nous arriverons la programmation oriente objet, vous verrez quun objet peut paratre singulier de lextrieur, mais pluriel de lintrieur, de mme quune classe dlves). Nous appelons scalaire une variable singulire, et tableau une variable plurielle. Comme une chane peut tre stocke dans une variable scalaire, nous pourrons crire une version un peu plus longue (et mieux commente) de notre premier exemple comme ceci :
$phrase = "Salut tout le monde !\n"; print $phrase; # Donner une valeur une variable. # Afficher la variable.

Remarquez que nous navons pas eu prdfinir le genre de la variable $phrase. Le caractre $ dit Perl que phrase est une variable scalaire, cest--dire quelle contient une valeur singulire. Une variable tableau, en revanche, commencerait par le caractre @ (on peut remarquer que $ est un S stylis, pour scalaire, alors que @ est un a stylis pour array , tableau en anglais). Perl connat dautres types de variables aux noms bizarres comme hachage , handle et typeglob . Tout comme les scalaires et les tableaux, ces types de variables sont galement prcds par des caractres tranges. Dans un souci dexhaustivit, voici la liste de tous les caractres tranges que vous pourrez rencontrer :

customer_8566

6
Type scalaire tableau hachage sous-programme typeglob Car. $ @ % & * Exemple $cents @large %interet &comment *truc

Chapitre 1 Vue densemble


Est un nom pour Une valeur propre (nombre, chane). Une liste de valeurs, indexes par numro. Un groupe de valeurs indexes par chane. Un bout de code Perl appelable. Tout ce qui est appel truc.

Pour certains puristes des langages, ces caractres tranges sont une raison dabhorrer Perl. Cette raison est superficielle. Ces caractres procurent de nombreux avantages : les variables peuvent tre interpoles dans des chanes sans syntaxe supplmentaire. Les scripts Perl sont faciles lire (pour ceux qui ont pris la peine dapprendre Perl !) parce que les noms se distinguent des verbes, et que de nouveaux verbes peuvent tre ajouts au langage sans abmer dautres scripts (nous vous avions dit que Perl tait conu pour voluer). Et lanalogie avec les noms na rien de frivole ; il existe de nombreux prcdents dans divers langages naturels qui requirent des marqueurs de noms grammaticaux. Enfin, cest notre avis !

Singularits
Daprs notre exemple, on voit que lon peut assigner une nouvelle valeur un scalaire avec loprateur =, comme dans de nombreux autres langages informatiques. On peut affecter nimporte quelle forme de valeur scalaire une variable SCALAIRE : entier, nombre virgule f lottante, chane, et mme des choses sotriques comme des rfrences dautres variables ou des objets. Il existe de nombreuses faons de gnrer ces valeurs assigner. Comme dans le shell UNIX4, il est possible demployer diffrents mcanismes de protection (quoting) pour fabriquer diffrents types de valeurs. Les doubles apostrophes font une interpolation de variable5 et une interprtation de lantislash (Comme en transformant \t en tabulation, \n en saut de ligne, \001 en contrle-A, etc., dans la tradition de nombreux programmes UNIX, alors que les apostrophes suppriment la fois linterpolation et linterprtation. Et les apostrophes inverses excutent un programme externe et renvoient la sortie du programme, ce qui fait que lon peut capturer une ligne unique contenant toutes les lignes de la sortie.
$reponse = 42; $pi = 3.14159265; $avocats = 6.02e23; $animal = "Chameau"; $signe = "Mon $animal et moi"; # # # # # un entier un nombre "rel" notation scientifique chane chane avec interpolation

4. Nous parlons ici de tous les clones UNIX comme BSD, Linux et Unix. 5. Parfois appele substitution par les programmeurs shell, mais nous prfrons rserver ce mot pour quelque chose dautre en Perl. Il vaut donc mieux parler dinterpolation. Nous employons ce terme dans son sens textuel ( Ce passage est une interpolation gnostique ) et non dans son sens mathmatique ( Ce point du graphe est une interpolation entre deux autres points ).

customer_8566

Langages naturels et artificiels


$cout = Cela cote $100; $pourquoi = $parceque; $x = $taupes * $avocats; $exit = system("vi $x"); $cwd = `pwd`; # # # # # chane sans interpolation une autre variable une expression code de retour dune commande chane gnre par une commande

Et mme si nous navons pas encore vu les valeurs exotiques, nous devons signaler que les scalaires peuvent rfrencer dautres types de donnes incluant les sous-programmes et les objets.
$ary = \@montableau; $hsh = \%monhachage; $sub = \&monsousprog; $ary = [1,2,3,4,5]; $hsh = {Na=>19, Cl=>35}; $sub = sub { print $pays }; $fido = new Chameau "Amelia"; # rfrence un tableau nomm # rfrence un hachage nomm # rfrence un sous-programme # rfrence un tableau anonyme # rfrence un hachage anonyme # rfrence un sous-programme anonyme # rfrence un objet

Les variables non initialises se mettent exister quand le besoin sen fait sentir. Daprs le principe de moindre surprise, elles sont cres avec une valeur nulle, que ce soit "" ou 0. Selon lendroit o elles sont utilises, les variables sont automatiquement interprtes comme des chanes, des nombres ou les valeurs vrai et faux (communment appeles valeurs boolennes). Les oprateurs attendent certains types de valeurs en paramtres, et nous dirons donc que ces oprateurs fournissent ou procurent un contexte scalaire ces paramtres. Nous serons parfois plus spcifiques et dirons quil fournit un contexte numrique, un contexte de chane ou un contexte boolen ces paramtres (nous parlerons plus loin du contexte de liste, qui est linverse du contexte scalaire). Perl convertit automatiquement les donnes sous la forme requise par le contexte courant, non sans raison. Par exemple, supposons que nous ayons crit ceci :
$chameaux = 123; print $chameaux + 1, "\n";

La valeur originelle de $chameaux est une chane, mais elle est convertie en un nombre pour y ajouter 1, puis reconvertie en chane pour tre affiche : "124". Le saut de ligne, reprsent par "\n", est galement dans un contexte de chane, mais puisquil est dj une chane, aucune conversion nest ncessaire. Mais remarquez que nous avons d employer des apostrophes doubles ; les apostrophes simples () autour de \n auraient donn une chane deux caractres constitue dun antislash suivi dun n, ce qui nest en rien un saut de ligne. Dune certaine manire, les apostrophes simples et doubles reprsentent donc un autre moyen de spcifier le contexte. Linterprtation du contenu dune chane protge dpend de la forme de protection utilise. Nous verrons plus loin certains autres oprateurs qui fonctionnent comme des protections de faon syntaxique, mais qui utilisent la chane dune manire spciale comme pour la correspondance de motifs ou la substitution. Ils fonctionnent tous comme des apostrophes doubles. Le contexte dapostrophe double est le contexte interpolatif de Perl et est fourni par de nombreux oprateurs qui ne ressemblent pas des guillemets.

customer_8566

Chapitre 1 Vue densemble

De la mme manire, une rfrence se comporte comme telle lorsque vous tes dans un contexte de drfrencement , sinon elle agit comme une simple valeur scalaire. Par exemple nous cririons :
$fido = new Chameau "Amelia"; if (not $fido) { die "chameau mort"; } $fido->seller();

Ici nous crons une rfrence lobjet Chameau et la plaons dans la variable $fido. la ligne suivante nous testons $fido dans un contexte boolen, et nous levons une exception si sa valeur est fausse, ce qui dans ce cas voudrait dire que le constructeur new Chameau a chou la cration de lobjet Chameau. Mais la dernire ligne, nous utilisons $fido comme rfrence pour trouver la mthode seller() applique lobjet rfrenc par $fido, qui se trouve tre un Chameau, et donc Perl cherche la mthode seller() pour lobjet Chameau. Nous reviendrons sur ce sujet. Souvenez-vous juste pour le moment que le contexte est important en Perl, car il sert lever toute ambigut sans faire aucune dclaration, contrairement beaucoup dautres langages.

Pluralits
Certains types de variables contiennent plusieurs valeurs qui sont logiquement lies entre elles. Perl connat deux types de variables multivaleurs : les tableaux et les hashes, tables de hachage (ou hachages). Ils se comportent comme des scalaires par de nombreux aspects. Ils se mettent exister quand le besoin sen fait sentir et ne contiennent alors rien. Quand on leur assigne une valeur, ils fournissent un contexte de liste du ct droit de lassignation. On emploie un tableau quand on veut chercher quelque chose par son numro. On emploie une table de hachage quand on veut chercher quelque chose par son nom. Ces deux concepts sont complmentaires. On voit souvent des gens utiliser un tableau pour traduire les numros de mois en noms, et un hachage correspondant pour traduire les noms en numros (les hachages ne se limitent videmment pas aux seuls nombres. Par exemple, il est possible davoir un hachage qui traduise les noms de mois en nom de pierres porte-bonheur). Tableaux. Un tableau est une liste ordonne de scalaires, indice par la position du scalaire dans la liste. Celle-ci peut contenir des nombres, ou des chanes, ou un mlange des deux (elle peut aussi contenir des rfrences dautres listes ou hachages). Pour assigner une liste de valeurs un tableau, il suffit de regrouper les variables (par des parenthses) :
@maison = ("lit", "chaise", "table", "poele");

Inversement, si lon utilise @maison dans un contexte de liste, comme ce que lon trouve droite dune assignation, on obtient la mme liste qui a t entre. On peut donc assigner quatre variables depuis le tableau comme ceci :
($Procuste, $porteurs, $multiplication, $gratter) = @maison;

Cest ce que lon appelle des assignations de liste. Elles se produisent logiquement en parallle, et il est possible de permuter deux variables en crivant :
($alpha,$omega) = ($omega,$alpha);

Tout comme en C, les tableaux dmarrent zro ; quand on parle des quatre premiers

customer_8566

Langages naturels et artificiels

lments dun tableau, leur numration court de 0 3.6 Les indices de tableaux sont entours de crochets [comme ceci], et si lon veut slectionner un seul lment du tableau, on sy rfre par $maison[n], o n est lindice (un de moins que le numro de llment) que lon dsire ; voyez lexemple ci-dessous. Puisque llment considr est un scalaire, il est toujours prcd dun $. Si lon veut valoriser un seul lment de tableau la fois, on crit lassignation prcdente comme suit :
$maison[0] $maison[1] $maison[2] $maison[3] = = = = "lit"; "chaise"; "table"; "poele";

Comme les tableaux sont ordonns, il existe plusieurs oprations utiles sy rapportant, comme les oprations de pile, push et pop. Une pile nest aprs tout quune liste ordonne, avec un dbut et une fin. Surtout une fin. Perl considre que la fin de la liste est le haut dune pile (bien que la plupart des programmeurs Perl pensent quune liste est horizontale, le haut de la pile tant droite). Hachages. Un hachage (hash en anglais) est un ensemble non ordonn de scalaires index par une valeur chane associe chaque scalaire. Cest pourquoi les hachages sont souvent appels tableaux associatifs . La principale raison pour laquelle leur appellation a chang est que tableau associatif est long crire pour les paresseux, et nous en parlons tellement souvent que nous avons dcid de prendre un nom plus bref.7 Ensuite, le terme hachage souligne le fait quil sagit de tables non ordonnes. Elle sont en fait implmentes grce un systme de recherche dans une table de hachage, ce qui leur donne leur rapidit, rapidit qui reste inchange quel que soit le nombre de valeurs prsentes. On ne peut pas faire de push ou de pop sur un hachage, parce que cela na aucun sens. Un hachage na ni dbut, ni fin. Les hachages sont nammoins trs puissants et trs utiles. Tant que vous ne penserez pas en terme de hachages, vous ne penserez pas en Perl. Puisque les clefs dun tableau associatif ne sont pas ordonnes, vous devez fournir la clef aussi bien que sa valeur lorsque celui-ci est rempli. Vous pouvez aussi bien lui affecter une liste comme pour un tableau ordinaire, mais chaque paire dlments sera interprte comme la paire clef/valeur. Les tableaux associatifs utilisent le symbole % pour sidentifier. (Pour mmoire, si vous regardez attentivement le caractre %, vous pouvez voir la clef et sa valeur avec entre deux le /.) Supposons que nous voulions traduire les abrviations des noms de jours en leurs correspondants complets. Nous pourrions crire cette assignation de liste :
%longjour = ("Dim", "Dimanche", "Lun", "Lundi", "Mar", "Mardi", "Mer", "Mercredi", "Jeu", "Jeudi", "Ven", "Vendredi", "Sam", "Samedi");
6. Si cela vous semble bizarre, pensez lindice comme un offset, un dplacement, cest--dire le nombre dlments qui le prcdent. Il ny en a videmment aucun avant le premier lment, qui a donc un offset de zro. Cest ainsi que pensent les ordinateurs (cest du moins ce que nous pensons). 7. Si tant est que lon puisse qualifier de bref quoi que ce soit ayant trait aux hachages...

customer_8566

10

Chapitre 1 Vue densemble

Figure 1-1. Un tableau et un hachage Comme il est parfois difficile de lire un hachage ainsi dfini, Perl fournit la squence => (gal, suprieur) comme alternative la virgule. Cette syntaxe (associe un formatage cratif) facilite la distinction entre clefs et valeurs.
%longjour "Dim" "Lun" "Mar" "Mer" "Jeu" "Ven" "Sam" ); = ( => "Dimanche", => "Lundi", => "Mardi", => "Mercredi", => "Jeudi", => "Vendredi", => "Samedi",

Il est non seulement possible dassigner une liste un hachage, comme nous lavons fait ci-dessus, mais si lon emploie un hachage dans un contexte de liste, celui-ci convertira le hachage en une liste de paires clef/valeurs dans un ordre quelconque. La plupart du temps, on se contente dextraire une liste des seules clefs, grce la fonction (bien nomme) keys. Elle est galement non ordonne mais peut tre facilement trie au besoin grce la fonction (bien nomme) sort. On peut alors utiliser les clefs ordonnes pour accder aux valeurs dans un ordre dtermin. Les hachages ntant quune forme volue de tableau, il suffit den slectionner un lment individuel en entourant la clef par des accolades. Cest ainsi que pour trouver la

customer_8566

Langages naturels et artificiels

11

valeur associe Mer dans le hachage ci-dessus, il faut crire $longjour{"Mer"}. Remarquez encore une fois quil sagit dune valeur scalaire et quil faut donc crire $ et non %. Dun point de vue linguistique, la relation code dans un hachage est gnitive ou possessive, comme les mots de , du ou d en franais. La femme dAdam est Eve, et nous pouvons crire :
$femme{"Adam"} = "Eve";

Complexits
La famille des tableaux et des hachages permet de reprsenter des structures de donnes simples et lgantes, mais dans la ralit le problme ne se pliera pas toujours cette simplicit. Il est parfois ncessaire de construire des structures de donnes non linaires. Perl nous permet de raliser ce type de structure dune manire trs simple. Il permet en effet de manipuler de simples scalaires qui se rfrent des tableaux. Nous le faisons tous les jours dans le langage courant lorsque nous utilisons un mot par exemple aussi complexe que gouvernement pour reprsenter une entit aussi complexe et inscrutable. (Cest un exemple parmi dautres.) Pour dvelopper notre exemple prcdent, supposons que nous parlons des femmes de Jacob et Adam. Jacob a eu quatre femmes. Nous pourrions penser lcrire de cette faon :
$femme{"Jacob"} = ("La", "Rachel", "Bilha", "Zilpa"); # MAUVAIS

Mais cette reprsentation nest pas bonne car mme les parenthses ne sont pas assez puissantes pour transformer une liste en scalaire. (Les parenthses sont utilises pour le groupage syntaxique et les virgules pour la sparation syntaxique.) Il faut indiquer Perl que cette liste doit tre un scalaire. Les crochets sont parfaitement adapts cette fin :
$femme{"Jacob"} = ["La", "Rachel", "Bilha", "Zilpa"]; # ok

Cette ligne cre un tableau anonyme et affecte sa rfrence llment associatif $femme{"Jacob"}. Ainsi nous avons un tableau associatif nomm contenant un tableau anonyme. Cest comme a que Perl traite les tableaux multidimensionnels et les structures de donnes imbriques. Comme avec les types tableaux, on peut aussi affecter des lments spars comme ceci :
$femme{"Jacob"}[0] $femme{"Jacob"}[1] $femme{"Jacob"}[2] $femme{"Jacob"}[3] = = = = "La"; "Rachel"; "Bilha"; "Zilpa";

Comme vous pouvez le voir, cela ressemble beaucoup un tableau multidimensionnel avec des coordonnes de chane puis numrique. Visualisons maintenant une structure de donnes imbriques sous forme darbre o nous listons aussi tous les fils de chacune des femmes de Jacob. Dans ce cas nous voulons utiliser le tableau associatif dans un contexte scalaire. Pour cela utilisons les accolades. (La valeur de la clef est un tableau entre crochets. Maintenant nous avons un tableau lintrieur dune association, elle-mme association.)
$filsDesFemmesDe{"Jacob"} = { "La" => ["Ruben", "Simon", "Lvi", "Juda", "Issachar", "Zabulon"],

customer_8566

12
"Rachel" => ["Joseph", "Benjamin"], "Bilha" => ["Dan", "Nephtali"], "Zilpa" => ["Gad", "Aser"], };

Chapitre 1 Vue densemble

Les lignes suivantes sont quivalentes :


$fils_des_femmes_de{"Jacob"}{"La"}[0] $fils_des_femmes_de{"Jacob"}{"La"}[1] $fils_des_femmes_de{"Jacob"}{"La"}[2] $fils_des_femmes_de{"Jacob"}{"La"}[3] $fils_des_femmes_de{"Jacob"}{"La"}[4] $fils_des_femmes_de{"Jacob"}{"La"}[5] $fils_des_femmes_de{"Jacob"}{"Rachel"}[0] $fils_des_femmes_de{"Jacob"}{"Rachel"}[1] $fils_des_femmes_de{"Jacob"}{"Bilha"}[0] $fils_des_femmes_de{"Jacob"}{"Bilha"}[1] $fils_des_femmes_de{"Jacob"}{"Zilpa"}[0] $fils_des_femmes_de{"Jacob"}{"Zilpa"}[1] = = = = = = = = = = = = "Ruben"; "Simon"; "Lvi"; "Juda"; "Issachar"; "Zabulon"; "Joseph"; "Benjamin"; "Dan"; "Nephtali"; "Gad"; "Aser";

On peut constater sur cet exemple que nous avons rajout une dimension supplmentaire notre tableau. Perl nous laisse le choix, mais la reprsentation interne est identique. Le point important noter ici est que Perl nous permet de reprsenter une structure de donnes complexes comme un simple scalaire. Cette encapsulation nous permet de construire une structure oriente objet. Lorsque nous avions invoqu le constructeur de Chameau comme ceci :
$fido = new Chameau "Amelia";

nous avions cr un objet Chameau reprsent par le scalaire $fido. Mais la structure intime de lobjet Chameau est plus complique. En tant que concepteurs dobjets, nous ne sommes pas concerns par ceci, moins dtre nous-mmes les implmenteurs des mthodes de cette classe. Mais, gnralement, un objet comme celui-ci serait reprsent par un tableau associatif contenant les attributs de Chameau, tels son nom ( Amelia dans ce cas, et non pas fido ), le nombre de bosses (ce que nous navons pas spcifi, mais il vaut probablement 1, regardez la couverture du livre).

Simplicit
Si votre tte ne tourne pas aprs avoir lu cette dernire section alors vous avez une grosse tte. La plupart des humains sont rebuts par les structures compliques du type gouvernement ou du type arbre gnalogique. Pour cette raison nous disposons dans notre langage parl dartifices qui cachent cette complexit sous-jacente. La technique la plus probante est la clture du champ smantique, lexicalisation, topicalization en anglais, qui permet de saccorder sur les termes du langage utilis. La consquence immdiate est une meilleure communication. La plupart dentre nous utilisent cette technique couramment pour basculer dun contexte smantique vers un autre lorsque nous changeons simplement de sujet de conversation. Perl dispose dans sa palette de ce type doutil. Lun de ceux-ci est fourni par la simple dclaration package. Supposons que notre sujet est le Chameau de Perl. On dclenche le module Chameau par la dclaration :

customer_8566

Langages naturels et artificiels


package Chameau;

13

Tout symbole dclar ensuite sera prfix par le nom du module Chameau:: . Ainsi si on crit :
package Chameau; $fido = &fetch();

on crit en ralit $Chameau::fido et la fonction appele est &Chameau::fetch, (nous parlerons des verbes plus tard). Si dans le cours du droulement du code, linterprteur rencontre le code suivant :
package Chien; $fido = &fetch();

il ne pourra confondre les noms rels car $fido est en fait $Chien::fido, et non $Chameau::fido. En informatique cela signifie un espace de nommage. Il na pas de limite cardinale. Perl nen connat quun la fois. La simplification est le choix libre du programmeur. Une chose remarquable est que dans :
$fido = new Chameau "Amelia";

nous invoquons le verbe &new dans le package Chameau, qui a pour nom plein &Chameau::new. et par
$fido->seller();

nous invoquons la routine &Chameau::seller, car $fido pointe sur un Chameau. Cest la programmation objet en perl. La dclaration package Chameau, marque le dbut dun paquetage, ici le paquetage Chameau. Parfois il suffit dutiliser les noms et les verbes dun paquetage existant. On utilise alors la dclaration use, qui charge le module dans linterprteur. Cela doit scrire :
use Chameau;

Puis on peut utiliser nos mthodes


$fido = new Chameau "Amelia";

Perl est WYSIWYG. Sinon Perl ne connatrait pas Chameau. La chose intressante ici est quil est juste ncessaire de connatre les capacits dun Chameau. Il suffit de trouver le module sur CPAN :
use Le::Cool::Module;

Alors on peut actionner les verbes de ce module dans le champ du sujet. La lexicalisation Perl, comme dans le langage naturel, donne un nom au champ lexical. Certains modules dfinissent des ensembles lexicaux et uniquement cela, pour linterprteur lui-mme. Ces modules spciaux se nomment pragmas. On verra souvent lutilisation du pragma strict de cette manire :
use strict;

Le pragma strict permet dajouter une norme pour lvaluation des termes par Perl. Cette norme oblige prciser certains aspects comme la porte des variables du code, ce qui est utile dans le dveloppement de grands projets. En effet, Perl est optimis pour lcriture de petits modules, mais avec cette directive de compilation il devient possible

customer_8566

14

Chapitre 1 Vue densemble

de grer des projets importants. On peut en effet lajouter tout moment dans des modules lmentaires, ce qui permet de les faire interagir dans un mme champ lexical. (Et autoriser du mme coup une approche objet dans le dveloppement de lapplication elle-mme.)

Verbes
Comme tous les langages informatiques impratifs, de nombreux verbes de Perl correspondent des commandes : elles disent linterprteur de Perl de faire quelque chose. En revanche, comme dans un langage naturel, les significations des verbes de Perl tendent sparpiller dans plusieurs directions selon le contexte. Une instruction commenant par un verbe est en gnral purement imprative et value entirement pour ses effets secondaires. Nous appelons souvent ces verbes procdures, surtout quand ils sont dfinis par lutilisateur. Un verbe frquemment rencontr (que vous avez dailleurs dj vu) est la commande print :
print "La femme dAdam est ", $femme{Adam}, ".\n";

Leffet secondaire produit la sortie dsire. Mais il existe dautres modes que le mode impratif. Certains verbes permettent dinterroger linterprteur sur certaines valeurs comme dans les conditionnelles comme if. Dautres verbes traduisent leurs paramtres dentre en valeurs de retour, tout comme une recette vous indique comment transformer des ingrdients de base en un rsultat (peut-tre) comestible. Nous appelons souvent ces verbes des fonctions, par dfrence envers des gnrations de mathmaticiens qui ne savent pas ce que signifie le mot fonctionnel en langage naturel. Un exemple de fonction interne est lexponentielle :
$e = exp(1); # 2.718281828459, ou peu prs

Mais Perl ne fait pas de distinction entre les procdures et les fonctions. Les termes seront employs de faon interchangeable. Les verbes sont parfois appels sous-programmes (subroutines) quand ils sont dfinis par lutilisateur, ou oprateurs (sils sont prdfinis). Mais appelez-les comme il vous plaira ; ils renvoient tous une valeur, quelle soit ou non significative, que vous pouvez ou non choisir dignorer. Au fur et mesure que nous avanons, nous verrons dautres exemples du comportement de Perl qui le font ressembler un langage naturel. Nous avons dj insidieusement prsent certaines notions de langage mathmatique, comme laddition et les indices, sans parler de la fonction exponentielle. Perl est aussi un langage de contrle, un langage dintgration, un langage de traitement de listes et un langage orient objet. Entre autres. Mais Perl est aussi un bon vieux langage informatique. Et cest ce quoi nous allons maintenant nous intresser.

Un exemple de notation
Supposons que vous ayez un ensemble de notes pour chaque membre dune classe dlves. Vous aimeriez une liste combine de toutes les notes pour chaque tudiant, plus leur moyenne. Vous disposez dun fichier texte (appel, quelle imagination,

customer_8566

Un exemple de notation
notes ) qui ressemble ceci :
Xavier 25 Samantha 76 Herv 49 Peter 66 Olivier 92 Thierry 42 Fred 25 Samantha 12 Herv 0 Corinne 66 etc.

15

Le script ci-dessous rassemble toutes leurs notes, dtermine la moyenne de chaque tudiant et les affiche dans lordre alphabtique. Ce programme suppose, plutt navement, quil nexiste pas deux Corinne dans votre classe. Cest--dire que sil y a un deuxime lment pour Corinne, le programme supposera quil sagit dune autre note de la premire Corinne. Au fait, les numros de lignes ne font pas partie du programme, toute ressemblance avec le BASIC mise part.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: #!/usr/bin/perl open(NOTES, "notes") or die "Ouverture des notes impossible : $!\n"; while ($ligne = <NOTES>) { ($etudiant, $note) = split(/ /, $ligne); $notes\{$etudiant\} .= $note . " "; } foreach $etudiant (sort keys %notes) { $scores = 0; $total = 0; @notes = split(/ /, $notes{$etudiant}); foreach $note (@notes) { $total += $note; $scores++; } $moyenne = $total / $scores; print "$etudiant: $notes{$etudiant}\tMoyenne : $moyenne\n"; }

Ne louchez pas ainsi. Nous devons avouer que si cet exemple illustre beaucoup de ce que nous avons dcrit jusqu prsent, il comprend certaines choses que nous allons maintenant expliquer. Mais si vous regardez un peu dans le vague, vous pouvez commencer voir apparatre certains motifs intressants. Vous pouvez vous livrer toutes les suppositions imaginables, et nous vous dirons plus tard si vous aviez raison. Nous pourrions vous dire dessayer de le lancer, mais peut-tre ne savez-vous pas comment faire.

customer_8566

16

Chapitre 1 Vue densemble

Comment faire
Bien. Vous devez tre en train de vous demander comment lancer un programme Perl. La rponse la plus courte est que vous le donnez au programme interprteur de Perl, qui sappelle justement perl (notez le p minuscule). Une rponse plus complte commence comme ceci : Il Existe Plus DUne Faon De Faire.8 La premire manire dinvoquer perl (qui fonctionne sur la plupart des systmes dexploitation) est dappeler explicitement perl depuis la ligne de commande.9 Si vous vous trouvez sur une version dUNIX et que ce que vous faites est relativement simple, vous pouvez utiliser loption -e (le % de lexemple suivant reprsentant une invite standard de shell, il ne faut pas le taper) :
% perl -e print "Salut tout le monde!\n";

Sous dautres systmes dexploitation, il faudra peut-tre jouer des apostrophes. Mais le principe de base est le mme : vous essayez de rentrer tout ce que Perl doit savoir en 80 colonnes.10 Pour les scripts plus longs, vous pouvez utiliser votre diteur favori (ou un autre) pour crire vos commandes dans un fichier, puis, si le script sappelle gradation , vous entrez :
% perl gradation

Vous invoquez toujours explicitement linterprteur Perl, mais au moins, vous navez pas tout mettre sur la ligne de commande chaque fois. Et vous navez pas jouer des apostrophes pour plaire au shell. La faon la plus commode dinvoquer un script est de simplement lappeler par son nom (ou de cliquer sur son icone), et de laisser le systme dexploitation trouver linterprteur tout seul. Sous certains systmes, il peut exister un moyen dassocier certaines extensions de fichier ou certains rpertoires une application particulire. Sur les systmes UNIX qui supportent la notation #! (appele shebang), la premire ligne du script peut tre magique et dire au systme dexploitation quel programme lancer. Mettez une ligne ressemblant11 la ligne 1 de notre exemple dans votre programme :
#!/usr/bin/perl

Tout ce quil vous reste crire est maintenant :


% gradation

Ce qui ne fonctionne videmment pas parce que vous avez oubli de rendre le script ex8. Theres More Than One Way To Do It : cest le slogan de Perl, et vous allez tre fatigu de lentendre, moins que vous ne soyez lExpert Local, auquel cas vous serez fatigu de le rpter. Il est quelquefois raccourci en TMTOWTDI, que lon prononce tim-toady . Mais vous pouvez le prononcer de la faon qui vous plat. Aprs tout, TMTOWTDI. 9. En supposant que vous disposez dune ligne de commande. Si vous travaillez avec un vieux Mac, vous aurez besoin de faire une mise jour vers le systme OS X. 10. Ce genre de script est souvent appel one-liner, une-ligne . Sil vous arrive de frquenter dautres programmeurs Perl, vous dcouvrirez que certains dentre eux sont friands de une-lignes. Perl a parfois t qualifi de langage en criture seule cause de ces voyous. 11. Si Perl ne se trouve pas dans /usr/bin, vous devrez changer la ligne #!.

customer_8566

Handles de fichiers

17

cutable (voir la page de manuel de chmod(1)12 et quil nest pas dans votre PATH. Dans ce cas, vous devrez fournir un nom de chemin complet pour que votre systme dexploitation sache comment trouver votre script. Quelque chose comme :
% ../bin/gradation

Enfin, si vous avez la malchance de travailler sur un ancien systme UNIX qui ne reconnat pas la ligne magique #!, ou si le chemin vers votre interprteur est plus long que 32 caractres (une limite interne sur certains systmes), vous pourrez contourner le problme comme ceci :
#!/bin/sh -- # perl, pour arrter de boucler eval exec /usr/bin/perl -S $0 ${1+"$@"} if 0;

Certains systmes dexploitation peuvent demander une modification de ce qui prcde pour grer, /bin/sh, DCL, COMMAND.COM, ou tout ce qui vous tient lieu dinterprteur de commandes. Demandez votre Expert Local. Tout au long de ce livre, nous nous contenterons demployer #!/usr/bin/perl pour reprsenter toutes ces notions et toutes ces notations, mais vous saurez quoi vous en tenir. Une astuce : quand vous crivez un script de test, ne lappelez pas test. Les systmes UNIX ont une commande test interne, qui sera excute la place de votre script. Appelez-le plutt essai. Une autre astuce : pendant que vous apprenez Perl, et mme quand vous croyez savoir ce que vous faites, nous vous suggrons dutiliser loption -w, surtout pendant le dveloppement. Cette option active toutes sortes de messages davertissement utiles et intressants (dans le dsordre). Loption -w peut tre place sur la ligne magique , comme ceci :
#!/usr/bin/perl -w

Maintenant que vous savez lancer votre programme Perl ( ne pas confondre avec le programme perl), revenons notre exemple.

Handles de fichiers
moins quil ne sagisse dun projet dIA modlisant un philosophe solipsiste, votre programme a besoin de communiquer avec le monde extrieur. Aux lignes 3 et 4 de notre exemple de notation, on voit le mot NOTES, qui illustre un autre type de donnes de Perl, le handle de fichier. Un handle de fichier est un nom que lon donne un fichier, un priphrique, une socket ou un pipe pour que vous puissiez vous souvenir de ce dont

12. Bien que Perl ait son lot de notations bizarres, celle-ci doit tout UNIX. chmod(1) signifie que vous devez vous reporter la page de manuel de la commande chmod la section 1 de votre manuel UNIX. Si vous entrez soit man 1 chmod, soit man -s 1 chmod (selon votre type dUNIX), vous devriez trouver tout ce que sait votre systme de la commande chmod. (Bien sr, si votre type dUNIX est Pas UNIX ! , vous devrez vous rfrer la documentation de votre systme pour la commande quivalente, supposer que vous en soyez pourvu. Votre consolation tant que, si cette commande existe, elle aura un meilleur nom que chmod.)

customer_8566

18

Chapitre 1 Vue densemble

vous parlez, et pour dissimuler certaines complexits, notamment relatives au tampons. (En interne, les handles de fichiers sont similaires aux streams dun langage comme C ou C++, ou aux canaux dE/S du BASIC.) Les handles de fichiers facilitent la gestion des entres et des sorties depuis plusieurs sources et vers plusieurs destinations. Cest sa capacit communiquer avec de nombreux fichiers et de nombreux processus qui fait de Perl un bon langage dintgration.13 On cre un handle de fichier et on lattache un fichier par la fonction open. open prend deux paramtres : le handle de fichier et le nom du fichier auquel on veut lassocier. Perl vous donne aussi quelques handles de fichier prdfinis (et dj ouverts). STDIN est le canal dentre standard du programme, alors que STDOUT en est le canal de sortie standard. Et STDERR est un canal de sortie supplmentaire pour que votre programme puisse faire des remarques part pendant quil transforme (ou essaye de transformer) votre entre en sortie.14 Comme lon peut utiliser la fonction open pour crer des handles de fichiers des fins diverses (entres, sorties, pipes), vous devrez pouvoir spcifier le comportement que vous dsirez. Il suffit dajouter des caractres au nom du fichier.
open(SESAME, open(SESAME, open(SESAME, open(SESAME, open(SESAME, open(SESAME, "nomdefichier"); "<nomdefichier "); ">nomdefichier "); ">>nomdefichier "); "| sortie_de_commande"); "entre de commande |"); # lire depuis un fichier existant # (idem, explicitement) # crer un fichier et y crire # ajouter un fichier existant # mettre en place un filtre de sortie # mettre en place un filtre dentre

On voit que le nom en question est quelconque. Une fois ouvert, le handle de fichier SESAME peut tre utilis pour accder au fichier, ou au pipe, jusqu ce quil soit explicitement ferm (avec, on sen doutait, close(SESAME)), ou si le handle de fichier est attach un autre fichier par un autre open sur le mme handle.15 Une fois le handle de fichier ouvert en entre (ou si vous dsirez utiliser STDIN), vous pouvez lire une ligne grce loprateur de lecture de ligne, <>. Il est galement connu

13. Sans oublier les qualits suivantes : il travaille sur 8 bits sans problme, il est intgrable, et on peut y intgrer dautres choses via ses modules dextension. Il est concis et travaille sans problme en rseau. Il est pour ainsi dire conscient de son environnement. Il est possible de linvoquer de bien des manires (comme nous lavons dj vu). Mais surtout, le langage lui-mme est assez souple pour quil soit possible de le faire circuler autour dun problme. On revient encore ce fameux concept de TMTOWTDI. 14. Ces handles de fichier sont typiquement attachs votre terminal et vous pouvez donc entrer des donnes vers votre programme et en voir le rsultat, mais ils peuvent aussi se rattacher des fichiers (ou quivalents). Perl fournit ces handles prdfinis parce que le systme dexploitation les fournit dj, dune faon ou dune autre. Sous UNIX, les processus hritent de lentre, de la sortie et de lerreur standard de leur processus pre, typiquement un shell. Lune des tches dun shell est de mettre en place ces f lux dE/S afin que le processus fils nait pas sen proccuper. 15. Louverture dun handle de fichier dj ouvert ferme implicitement le premier fichier, le rendant ainsi inaccessible ce handle, et ouvre un fichier diffrent. Il faut faire attention ce que lon veut vraiment faire. Cela se produit parfois accidentellement, comme quand lon crit open($handle, $fichier), et que $handle contient une chane constante. Assurez-vous dassigner $handle, ou vous ne ferez quouvrir un nouveau fichier sur le handle nul.

customer_8566

Oprateurs

19

sous le nom doprateur diamant en raison de sa forme. Loprateur diamant entoure le handle de fichier <SESAME> dont on veut lire des lignes.16 Un exemple utilisant le handle de fichier STDIN pour lire une rponse fournie par lutilisateur ressemblerait ceci :
print STDOUT "Entrez un nombre : "; $nombre = <STDIN>; print STDOUT "Le nombre est $nombre\n"; # demander un nombre # entrer le nombre # afficher le nombre

Avez-vous vu ce que nous venons de vous glisser sous les pieds ? Quest-ce que ce STDOUT fait dans ces instructions print ? Cest simplement une des faons possibles dutiliser un handle de fichier. Un handle de fichier peut tre fourni comme premier argument de linstruction print et, sil est prsent, il indique o est la sortie. Dans ce cas, le handle de fichier est redondant, car la sortie aurait, de toute manire, t STDOUT. De mme que STDIN est lentre par dfaut, STDOUT est la sortie par dfaut (nous lavons enlev en ligne 18 de lexemple de notation pour viter de vous embrouiller). Nous avons fait autre chose. Si vous essayez lexemple ci-dessus, vous pouvez voir apparatre une ligne vide supplmentaire. En effet, la lecture nenlve pas automatiquement le saut de ligne de votre ligne dentre (qui serait par exemple 9\n ). Au cas o vous voudriez enlever le saut de ligne, Perl fournit les fonctions chop et chomp. chop enlve (et renvoie) le dernier caractre quon lui passe sans se poser de question, alors que chomp nenlve que le marqueur de fin denregistrement (en gnral, "\n") et renvoie le nombre de caractres enlevs. Cette expression est souvent employe pour lire une seule ligne :
chop($nombre = <STDIN>); # lire le nombre et enlever le saut de ligne # lire le nombre # enlever le saut de ligne

ce qui est identique


$number = <STDIN>; chop($number);

Oprateurs
Comme nous lavons laiss entendre plus haut, Perl est galement un langage mathmatique. Cest vrai diffrents niveaux, depuis les oprations logiques au niveau binaire jusquaux manipulations de nombres et densembles, de prdicats plus vastes diverses abstractions. Et comme nous le savons tous depuis que nous avons tudi les mathmatiques lcole, les mathmaticiens adorent les symboles tranges. Pire encore, les informaticiens ont invent leur propre version de ces symboles. Perl en connat un certain nombre, mais vous pouvez respirer car la plupart sont directement emprunts au C, au FORTRAN, sed ou awk, et seront donc familiers aux utilisateurs de ces langages. Vous pouvez vous fliciter de connatre plus de termes lexicaux, autant de point dentre vers les autres langages. Les oprateurs internes de Perl peuvent tre classs par nombre doprandes, en oprateurs unaires, binaires et ternaires. Ils peuvent tre classs par oprateurs infixes ou pr-

16. Loprateur diamant par dfaut, <>, lit des lignes depuis tous les fichiers spcifis sur la ligne de commande, ou depuis STDIN si aucun na t spcifi (ce comportement est standard pour de nombreux programmes filtres UNIX).

customer_8566

20

Chapitre 1 Vue densemble

fixes, mais aussi par le type dobjet avec lesquels ils travaillent, comme les nombres, les chanes ou les fichiers. Nous vous donnerons plus loin une table de tous les oprateurs, mais en voici quelques-uns par lesquels vous pourrez commencer.

Quelques oprateurs darithmtique binaire


Les oprateurs arithmtiques font exactement ce que lon peut attendre deux aprs les avoir tudis lcole.
Exemple $a + $b $a * $b $a % $b $a ** $b Nom Addition Multiplication Modulo Puissance Rsultat Somme de $a et de $b. Produit de $a et de $b. Reste de $a divis par $b. $a puissance $b.

Oui, nous avons bien laiss de ct la soustraction et la division. Mais vous devez pouvoir deviner comment celles-ci fonctionnent. Essayez-les et voyez si vous aviez raison (ou trichez et cherchez dans le chapitre 3, Oprateurs unaires et binaires.) Les oprateurs arithmtiques sont valus dans lordre habituel (cest--dire la puissance avant la multiplication, et la multiplication avant laddition). Les parenthses servent modifier lordre.

Oprateurs sur les chanes


Il existe galement un oprateur d addition pour les chanes, qui effectue leur concatnation. Contrairement dautres langages qui le confondent avec laddition arithmtique, Perl dfinit un oprateur distinct (.) pour cette opration.
$a = 123; $b = 456; print $a + $b; print $a . $b;

# affiche 579 # affiche 123456

Il existe aussi un oprateur de multiplication pour les chanes, galement appele rptition. Il sagit encore dun oprateur distinct (x) qui le diffrencie de la multiplication numrique :
$a = 123; $b = 3; print $a * $b; print $a x $b;

# affiche 369 # affiche 123123123

Loprateur de rptition est un peu inhabituel en ce quil prend une chane pour son argument de gauche et un nombre pour celui de droite. Remarquez galement comment Perl convertit automatiquement les nombres en chanes. Tous les nombres ci-dessus pourraient tre protgs par des apostrophes doubles avec le mme rsultat. La conversion interne se serait par contre produite dans le sens inverse (cest--dire de chanes vers des nombres).

customer_8566

Oprateurs

21

Il faut encore penser quelques dtails. La concatnation de chanes est galement implicite dans linterpolation qui se produit dans des chanes entre doubles apostrophes. Quant une liste de valeurs est affiche, les chanes de caractres sont en fait concatnes. Les trois instructions suivantes produisent donc le mme rsultat :
print $a . est gal . $b . "\n"; print $a, est gal , $b, "\n"; print "$a est gal $b\n"; # oprateur point # liste # interpolation

Le choix de celui quil convient dutiliser ne dpend que de vous. Loprateur x peut sembler relativement inutile premire vue, mais il trouve son utilit dans des cas comme celui-ci :
print "-" x $lrgecr, "\n";

Ceci trace une ligne travers lcran, supposer que sa largeur soit $lrgecr.

Oprateurs daffectation
Bien quil ne sagisse pas vraiment dun oprateur mathmatique, nous avons dj employ en de nombreuses occasions loprateur dassignation simple, =. Essayez de vous souvenir que = signifie est mis au lieu de gale (il existe aussi un oprateur dgalit mathmatique == qui signifie gale , et si vous commencez rf lchir tout de suite la diffrence entre les deux, vous aurez beaucoup moins mal la tte plus tard. Loprateur == est comme une fonction qui renvoie une valeur boolenne, alors que = est comme une procdure value dont leffet est de modifier une variable). De mme que les oprateurs prcdents, les oprateurs dassignation sont des oprateurs binaires infixes, ce qui veut dire quils ont un oprande de chaque ct de loprateur. Loprande de droite peut tre nimporte quelle expression, mais celui de gauche doit tre une lvalue correcte (ce qui, traduit en bon franais, signifie un emplacement de stockage valide, comme une variable ou un lment de tableau). Loprateur dassignation le plus courant est lassignation simple. Il dtermine la valeur de lexpression sa droite, puis met la variable sa gauche cette valeur :
$a = $b; $a = $b + 5; $a = $a * 3;

Remarquez que la dernire assignation se rfre deux fois la mme variable ; une fois pour le calcul et une autre pour lassignation. Rien dextraordinaire cela, mais cette opration est assez commune pour quelle connaisse une abrviation (emprunte au C). Si lon crit :
lvalue oprateur= expression

cela sera valu comme si ctait :


lvalue = lvalue oprateur expression

sauf que la lvalue nest pas calcule deux fois. On ne peroit de diffrence que si lvaluation de la lvalue a un effet secondaire. Mais quand il y a une diffrence, loprateur fait gnralement ce que vous vouliez. On peut, par exemple, crire :
$a *= 3;

customer_8566

22

Chapitre 1 Vue densemble

ce qui se lit multiplier $a par 3 et laffecter $a . Presque tous les oprateurs binaires de Perl le permettent, et mme certains de ceux qui ne le peuvent pas en C :
$ligne .= "\n"; # Ajouter un saut de ligne $ligne. $fill x= 80; # Rpter $fill 80 fois sur elle-mme. $val ||= "2"; # Mettre $val 2 si ce nest pas dj le cas.

La ligne 6 de notre exemple17 de notation contient deux concatnations de chanes, dont lune est un oprateur daffectation. Et la ligne 14 contient un +=. Quel que soit le type doprateur daffectation utilis, la valeur finale qui est renvoye est celle de laffectation complte18. Ceci ne surprendra pas les programmeurs C qui le savait dj en crivant
$a = $b = $c = 0;

pour initialiser 0 toutes les variables. Ce qui par contre les surprendra est que laffectation Perl retourne en lvalue la variable elle-mme, de telle sorte quil est possible en une instruction de le modifier deux fois, cest pourquoi nous pouvons crire :
($temp -= 32) *= 5/9;

pour faire la conversion en ligne Fahrenheit vers Celsius. Cest aussi pourquoi nous avons pu crire plus haut dans ce chapitre :
chop($nombre = <STDIN>);

pour que la valeur finale de $nombre soit modifie par chop. Pour rsumer, on peut utiliser cette fonctionalit chaque fois que lon veut faire une copie suivie dune modification de variable. Ce truc peut tre utilis pour faire deux choses sur la mme ligne Perl.

Oprateurs arithmtiques unaires


Comme si $variable += 1 ntait pas assez court, Perl emprunte au C un moyen encore plus concis dincrmenter une variable. Les oprateurs dautoincrmentation et dautodcrmentation ajoutent (ou soustraient) un la valeur de la variable. Ils peuvent tre placs avant ou aprs cette variable, ce qui dtermine le moment de leur valuation.
Exemple ++$a, $a++ --$a, $a-Nom Autoincrmentation Autodcrmentation Rsultat Ajouter 1 $a. Soustraire 1 de $a.

Si lon place lun des oprateurs auto avant la variable, il sagit dune variable princrmente (ou prdcrmente). Sa valeur sera modifie avant son rfrencement. Sil est

17. Vous ne lavez pas oubli ? 18. Ce qui diffre du Pascal, par exemple, o laffectation est une instruction et na pas de valeur. Nous avons dit que laffectation est comme un procdure, mais souvenez-vous quen Perl les procdures aussi ont une valeur.

customer_8566

Oprateurs

23

plac aprs la variable, il sagit dune variable post-incrmente (ou post-dcrmente) et sa valeur est modifie aprs son utilisation. Par exemple :
$a = 5; $b = ++$a; $c = $a--; # $a prend la valeur 5 # $b prend la valeur incrmente de $a, soit 6 # $c prend la valeur 6, puis $a passe 5

La ligne 15 de notre exemple de notation incrmente de un le nombre de notes, afin que nous puissions calculer la moyenne. Nous utilisons un oprateur de postincrmentation ($scores++), mais cela na pas dimportance dans ce cas puisque lexpression se trouve dans un contexte vide, ce qui nest quune faon particulire de dire que lexpression nest value que pour leffet secondaire de lincrmentation de la variable. La valeur renvoye est jete au panier.19

Oprateurs logiques
Les oprateurs logiques, que lon connat galement sous le nom doprateurs courtcircuit , permettent au programme de prendre des dcisions en fonction de critres multiples sans utiliser les conditionnelles imbriques. On les appelle court-circuit car ils arrtent lvaluation de leur argument de droite si largument de gauche suffit dterminer la valeur globale. Perl a en fait deux ensembles doprateurs logiques : lun deux, plutt poussireux, emprunt au C, et un superbe ensemble tout neuf doprateurs prcdence ultra-basse qui analysent plus comme ce quon en attend (mais ils se comportent de la mme faon une fois analyss). Perl possde deux ensembles doprateurs logiques, lun dit traditionnel emprunt au C, lautre avec une prcdence encore plus faible venant du BASIC. Lun a la prcdence la plus forte des oprateurs du langage, lautre la plus faible. Souvent les expressions sont quivalentes, cest une question de prfrences. (Pour une comparaison, voir la section And, or, not et xor logiques au chapitre 3.) Bien quils ne sont pas interchangeables, cause de la prcdence, une fois parss ils sexcutent avec le mme code. La prcdence prcise ltendue locale de arguments. Tableau 1-1. Oprateurs logiques
Exemple $a && $b $a || $b ! $a $a and $b $a or $b not $a $a xor $b Nom Et Ou Non Et Ou Non Ou exclusif Rsultat $a si $a est faux, $b sinon. $a si $a est vrai $b sinon. Vrai si $a nest pas vrai. $a si $a est faux, $b sinon. $a si $a est vrai, $b sinon. Vrai si $a nest pas vrai. Vrai si $a ou $b est vrai, mais pas les deux.

19. Et en fait, loptimisateur le remarque et optimise la post-incrmentation en princrmentation, qui est un peu plus efficace lexcution (ce que vous navez pas vraiment besoin de savoir, mais nous pensions que cela pouvait vous intresser).

customer_8566

24

Chapitre 1 Vue densemble

Puisque les oprateurs logiques court-circuitent , ils sont souvent utiliss pour excuter du code de manire conditionnelle. La ligne suivante (de notre exemple de notation) essaie douvrir le fichier notes . Si elle peut ouvrir le fichier, elle saute la ligne suivante du programme. Dans le cas contraire, elle affiche un message derreur et arrte lexcution.
open(NOTES, "notes") or die "Ouverture du fichier notes impossible: $!\n";

Littralement, Ouvrir notes ou mourir ! est encore un exemple de langage naturel, et les oprateurs de court-circuit prservent le f lux visuel. Les actions importantes sont listes en bas gauche de lcran et les actions secondaires sont caches droite. (La variable $! contient le message derreur renvoy par le systme dexploitation ; voir le chapitre 28, Noms spciaux.) Bien sr, ces oprateurs logiques peuvent aussi tre employs dans des constructions plus traditionnelles, comme les instructions if et while.

Oprateurs de comparaison
Les oprateurs de comparaison, ou relationnels, nous indiquent la relation existant entre deux valeurs scalaires (nombres ou chanes). Il existe deux ensembles doprateurs, dont lun effectue les comparaisons numriques et lautre des comparaisons de chanes. (Dans les deux cas, les arguments seront dabord transtyps, contraints , pour prendre le bon type.) Le tableau suivant suppose que $a et $b sont respectivement les arguments de gauche et de droite.
Comparaison gal Diffrent Infrieur Suprieur Infrieur ou gal Suprieur ou gal Comparaison Numrique == != < > <= >= <=> Chane eq ne lt gt le ge cmp Valeur de retour Vrai si $a est gal $b. Vrai si $a nest pas gal $b. Vrai si $a est plus petit que $b. Vrai si $a est plus grand que $b. Vrai si $a est infrieur ou gal $b. Vrai si $a est suprieur ou gal $b. 0 si gal, 1 si $a sup., -1 si $b sup.

On peut penser que les deux derniers oprateurs (<=> et cmp) sont entirement redondants. Vous avez raison. Cependant, ils sont incroyablement utiles dans les sous-programmes de tri (sort).20

20. Certains voient en la redondance le mal incarn car elle interdit un langage dtre minimaliste, ou orthogonal . Mais Perl nest pas orthogonal, il est diagonal . Nous entendons par ceci que Perl ne vous force pas tourner sans arrt angle droit. Il vaut parfois mieux suivre lhypothnuse du triangle pour aller o lon veut. Qui dit TMTOWTDI dit courts-circuits. Qui dit courts-circuits dit efficacit.

customer_8566

Structures de contrle

25

Oprateurs de tests de fichier


Les oprateurs de tests de fichier permettent de tester si certains attributs de fichier sont positionns avant de faire aveuglment nimporte quoi avec ces fichiers. Par exemple, il vaut mieux sassurer que le fichier /etc/passwd existe dj avant de louvrir en cration, effaant ainsi tout ce qui sy trouvait auparavant.
Exemple -e $a -r $a -w $a -d $a -f $a -T $a Nom Existe Lecture criture Rpertoire Fichier Fichier texte Rsultat Vrai si le fichier nomm par $a existe. Vrai si le fichier nomm par $a est accessible en lecture. Vrai si le fichier nomm par $a est accessible en criture. Vrai si le fichier nomm par $a est un rpertoire. Vrai si le fichier nomm par $a est un fichier rgulier. Vrai si le fichier nomm par $a est un fichier texte.

En voici quelques exemples :


-e "/usr/bin/perl" or warn "Perl est mal install\n"; -f "/boot" and print "Flicitations, nous devons tre sous Unix BSD\n";

Remarquez quun fichier rgulier nest pas la mme chose quun fichier texte. Les fichiers binaires comme /vmunix sont des fichiers rguliers, mais ne sont pas des fichiers texte. Les fichiers texte sont linverse des fichiers binaires, alors que les fichiers rguliers sont linverse des fichiers irrguliers comme les rpertoires et les priphriques. Il existe beaucoup doprateurs de test de fichier, dont un grand nombre nont pas t cits. La plupart sont des oprateurs boolens unaires : ils ne prennent quun seul oprande, un scalaire qui donne un fichier ou un handle de fichier, et ils renvoient une valeur vraie ou fausse. Quelques-uns renvoient une valeur plus complexe comme la taille du fichier ou son ge, mais vous pourrez les rechercher en temps utile dans la section Oprateurs unaires nomms et de test de fichier au chapitre 3.

Structures de contrle
Jusquici, et hormis notre programme de notation, tous nos exemples taient compltement linaires ; toutes les commandes taient excutes dans lordre. Nous avons vu quelques exemples dutilisation des oprateurs court-circuit permettant lexcution conditionnelle dune commande. Bien que certains programmes linaires savrent extrmement utiles (cest le cas de beaucoup de scripts CGI), on peut crire des programmes bien plus puissants grce aux expressions conditionnelles et aux mcanismes de boucles, que lon appelle structures de contrle. Perl peut donc tre considr comme un langage de contrle. Mais pour contrler le cours des choses, il faut tre en mesure de dcider, et pour dcider des choses, il faut distinguer le vrai du faux.

customer_8566

26

Chapitre 1 Vue densemble

Quest-ce que la vrit ?


Nous avons dj parl de la vrit21 et nous avons mentionn que certains oprateurs renvoient une valeur vraie ou fausse. Avant de continuer, nous devons expliquer exactement ce que nous entendons par l. Perl ne traite pas tout fait la vrit comme les autres langages informatiques, mais son comportement prend tout son sens avec un peu dhabitude. (En fait, nous esprons quil prendra tout son sens aprs avoir lu ce qui suit.) la base, Perl estime que la vrit est vidente en soi . Cest une faon un peu spcieuse de dire que lon peut valuer presque nimporte quoi pour connatre sa valeur de vrit. Perl emploie en pratique des dfinitions de la vrit qui dpendent du type de ce que lon est en train dvaluer. Il se trouve quil existe beaucoup plus de types de vrit que de types de non-vrit. La vrit en Perl est toujours value dans un contexte scalaire (sinon, aucun transtypage nest effectu). Voici donc les rgles des divers types de valeurs quun scalaire peut contenir : 1. Toute chane est vraie sauf "" et "0". 2. Tout nombre est vrai sauf 0. 3. Toute rfrence est vraie. 4. Toute valeur indfinie est fausse. En fait, les deux dernires rgles peuvent tre drives des deux premires. Toute rfrence (rgle 3) pointe vers quelque chose avec une adresse, et donne un nombre ou une chane contenant cette adresse, qui nest jamais nulle. Et toute valeur indfinie (rgle 4) donne 0 ou la chane nulle. Et dune certaine manire, il est possible de faire driver la rgle 2 de la rgle 1 si lon pose que tout est une chane. Encore une fois, aucun transtypage nest effectu pour valuer la vrit, mais mme si ctait le cas, une valeur numrique de 0 donnerait simplement la chane "0" et serait fausse. Tout autre nombre donnerait autre chose et serait vrai. Quelques exemples nous permettront de saisir un peu mieux ce que cela implique :
0 # deviendrait la chane "0", donc faux 1 # deviendrait la chane "1", donc vrai 10 - 10 # 10-10 vaut 0, deviendrait la chane "0", donc faux 0.00 # devient 0, et donc la chane "0", donc faux "0" # la chane "0", donc faux "" # une chane nulle, donc faux "0.00" # la chane "0.00", ni vide, ni vraiment "0", donc vrai "0.00" + 0 # le nombre 0 (transtyp par +), donc faux \$a # une rfrence $a, donc vrai, mme si $a est faux undef() # une fonction renvoyant la chane indfinie, donc faux

Comme nous avons dj dit que la vrit tait value dans un contexte scalaire, on peut se demander quelle serait la valeur dune liste. En fait, il nexiste pas dopration renvoyant une liste dans un contexte scalaire. Toutes renvoient une valeur scalaire et il suffit dappliquer les rgles de vrit ce scalaire. Il ny a donc pas de problme, tant que lon sait ce quun oprateur donn renvoie dans un contexte scalaire.
21. dire vrai, ce nest pas tout fait exact.

customer_8566

Structures de contrle

27

Les instructions if et unless


Nous avons vu plus haut comment un oprateur logique pouvait fonctionner comme un conditionnel. Une forme un peu plus complexe des oprateurs logiques est linstruction if. Celui-ci value une condition de vrit et excute un bloc si la condition est vraie.
if ($debug_level > 0) { # Quelque chose ne va pas. Il faut avertir lutilisateur. print "Debug: Danger, Arthur Accroc, danger!\n"; print "Debug: La rponse est 54 au lieu de 42.\n"; }

Un bloc consiste en une ou plusieurs instructions regroupes par un ensemble daccolades. Puisque linstruction if excute un bloc, les accolades sont ncessaires par dfinition. Dans un langage comme le C, on constate une certaine diffrence. Les accolades sont optionnelles sil ny a quune ligne de code, ce qui nest pas le cas en Perl. Parfois, il ne suffit pas dexcuter un bloc quand une condition est remplie. On dsire galement excuter un autre bloc quand la condition nest pas remplie. Bien que lon puisse videmment employer deux instructions if, lune tant la ngation de lautre, Perl fournit une solution plus lgante. Aprs le bloc, if peut prendre une deuxime condition optionnelle, appele else, qui nest excute que si la conditionnelle est fausse (les vtrans de linformatique nen seront pas surpris). En dautres occasions, vous pouvez mme avoir plus de deux choix possibles. En ce cas, il est possible dajouter une conditionnelle elsif pour les autre choix possibles (les vtrans de linformatique stonneront bon droit de la faon dcrire elsif , mais personne ici ne sen excusera).
if ($city eq "Lille") { print "Lille est au nord de Paris.\n"; } elsif ($city eq "Nancy") { print "Nancy est lest de Paris.\n"; } elsif ($city eq "Bayonne") { print "Bayonne est au sud-ouest de Paris. Et il y fait plus chaud!\n"; } else { print "Je ne sais pas o se trouve $city, dsol.\n"; }

Les clauses if et elsif sont calcules chacune leur tour, jusqu ce que lune dentre elles soit vraie ou que la condition else soit atteinte. Quand lune de ces conditions est vraie, son bloc est excut et toutes les branches restantes sont sautes. Parfois, on ne veut faire quelque chose que si la condition est fausse, et rien si elle est vraie. Un if vide avec un else nest pas trs propre, et la ngation dun if peut tre illisible ; il est dommage dcrire faire quelque chose si pas ceci est vrai . Dans ce cas, on peut utiliser linstruction unless.
unless ($destination eq $maison) { print "Je ne rentre pas la maison.\n"; }

Il nexiste pas de elsunless. Il sagit l dune caractristique.

customer_8566

28

Chapitre 1 Vue densemble

Constructions itratives (en boucle)


Perl possde quatre types principaux dinstructions itratives : while, until, for et foreach. Ces instructions permettent un programme Perl dexcuter de faon rptitive le mme code pour diffrentes valeurs.

Les instructions while et until


Les instructions while et until fonctionnent de la mme manire que les instructions if et unless, sauf quils rptent lexcution du bloc en bouclant. Dabord, la partie conditionnelle dune instruction est vrifie. Si la condition est remplie (si elle est vraie pour un while ou fausse pour un until), le bloc de linstruction est excut.
while ($tickets_vendus < 10000) { $dispo = 10000 - $tickets_vendus; print "$dispo tickets sont disponibles. Combien en voulez -vous: "; $achat = <STDIN>; chomp($achat); $tickets_vendus += $achat; }

Remarquez que si la condition originelle nest pas remplie, on ne rentrera jamais dans la boucle. Par exemple, si nous avons dj vendu 10 000 tickets, nous voulons que la ligne suivante du programme affiche quelque chose comme :
print "Ce spectacle est complet, revenez plus tard.\n";

Dans notre exemple de notation, on voit la ligne 4 :


while ($ligne = <NOTES>) {

ce qui assigne la ligne suivante la variable $ligne, et comme nous lavons expliqu plus haut, renvoie la valeur de $ligne afin que la condition de linstruction while puisse valuer la vrit de $ligne. On peut se demander si Perl obtient un faux \ sur les lignes vides et sort prmaturment de la boucle. La rponse est non. La raison en est simple, si vous vous reportez tout ce que nous en avons dit. Loprateur dentre de ligne laisse le saut de ligne la fin de la chane, ce qui fait quune ligne vide comporte la valeur "\n". Et vous savez que "\n" nest pas une des valeurs canoniques de fausset. La condition est donc vraie et la boucle continue mme pour les lignes vides. En revanche, quand nous atteignons la fin du fichier, loprateur dentre de ligne renvoie la valeur indfinie, qui donne toujours faux. Et la boucle se termine ainsi au moment dsir. Ce programme Perl na pas besoin dun test explicite sur la fonction eof, parce les oprateurs dentre sont conus pour fonctionner sans douleur dans un contexte conditionnel. En fait, presque tout est conu pour fonctionner sans douleur dans un contexte conditionnel. Par exemple, un tableau dans un contexte scalaire renvoie sa longueur. On voit donc frquemment ce genre de choses :
while (@ARGV) { process(shift @ARGV); }

La boucle sort automatiquement quand @ARGV est puis. Loprateur shift retire un lment de la liste argument chaque boucle et retourne cet lment. La boucle sarrte

customer_8566

Structures de contrle

29

automatiquement lorsque le tableau @ARGV est vide, donc de longueur 0 qui a pour valeur boolenne 0.22

Linstruction for
Un autre traitement itratif est la boucle for. Une boucle for tourne exactement comme la boucle while, mais parat trs diffrente (bien quelle dise quelque chose aux programmeurs C).
for ($vendu = 0; $vendu < 10000; $vendu += $achat) { $dispo = 10000 - $vendu; print "$dispo tickets sont disponibles. Combien en voulez-vous: "; $achat = <STDIN>; chomp($achat); }

La boucle for prend trois expressions entre les parenthses de la boucle : une expression pour initialiser ltat de la variable de boucle, une condition pour tester la variable et une expression pour modifier ltat de la variable. Quand la boucle commence, la variable est initialise et la condition est vrifie. Si elle est vraie, le bloc est excut. Quand le bloc se termine, lexpression de modification est excute, la condition est de nouveau vrifie et si elle est vraie, le bloc est rexcut avec les nouvelles valeurs. Tant que la condition reste vraie, le bloc et lexpression de modification continuent tre excuts. (Notez que seule la valeur de lexpression du milieu est value et mmorise, les deux autres ne sont utilises que comme effet de bord, et ne sont pas mmorises.)

Linstruction foreach
La dernire des principales instructions itratives est linstruction foreach. foreach est utilise pour excuter le mme code pour chacun des lments dun ensemble connu de scalaires, comme un tableau :
foreach $user (@users) { if (-f "$home{$user}/.nexrc") { print "$user est un type bien... il utilise un vi qui comprend Perl!\n"; } }

la diffrence des conditionnelles if et while, qui induisent un contexte scalaire dans lexpression, linstruction foreach induit un contexte de liste dans lexpression entre parenthses. Ainsi lexpression svalue en une liste (mme si cette liste ne contient quun scalaire). Chaque lment de la liste est tour tour mis dans la variable de boucle et le bloc de code est excut une fois par lment. Remarquez que la variable de boucle devient une rfrence llment lui-mme, et non une copie de llment. La modification de cette variable modifie donc le tableau originel.

22. Cest ainsi quon raisonne en Perl. Il nest pas ncessaire de comparer 0 avec 0 pour savoir que cest faux. Si certains langages vous y obligent, ne vous garez pas faire la comparaison explicite while (@ARGV != 0). Cest une perte de temps pour vous et le calculateur, aussi bien que pour la maintenance.

customer_8566

30

Chapitre 1 Vue densemble

On trouve beaucoup plus de boucles foreach dans un programme Perl typique que dans des boucles for, car il est trs facile en Perl de gnrer les listes que demande foreach. Une tournure que lon rencontre frquemment est une itration bouclant sur les clefs tries dun hachage :
foreach $clef (sort keys %hash) {

Ce qui est exactement le cas de la ligne 9 de notre exemple de notation.

Pour sen sortir : next et last


Les oprateurs next et last permettent de modifier le f lux de votre boucle. Il nest pas rare de rencontrer un cas spcial ; on peut vouloir le sauter, ou quitter la boucle quand on le rencontre. Par exemple, si lon gre des comptes UNIX, on peut vouloir sauter les comptes systme comme root ou lp. Loprateur next permet de sauter la fin de litration courante et den commencer une nouvelle. Loprateur last permet de sauter la fin du bloc comme si la condition du test avait renvoy faux, par exemple dans le cas o lon cherche un compte spcifique et que lon veut quitter aussitt quon la trouv.
foreach $user (@users) { if ($user eq "root" or $user eq "lp") { next; } if ($user eq "special") { print "Compte spcial trouv.\n"; # Traitement last; } }

Il est possible de sortir de boucles imbriques en les tiquetant et en spcifiant celles dont on veut sortir. Les modificateurs dinstruction (une autre forme de conditionnelle dont nous navons pas encore parl) associs ceci peuvent fournir des sorties de boucles trs lisibles, pour autant que le franais ou langlais soient lisibles :
LIGNE: while ($ligne = <ARTICLE>) { last LIGNE if $ligne eq "\n"; # arrt sur la premire ligne vide next LIGNE if /^#/; # sauter les lignes de commentaire # ici, votre publicit }

Vous devez vous dire, Une minute, l, quest ce que ce truc bizarre, ^#, entre ces espces de cure-dents ? Cela ne ressemble pas du langage naturel. . Vous avez mille fois raison. Il sagit dune recherche de correspondance contenant une expression rationnelle (bien quelle soit plutt simple). Et cest ce dont parle la section suivante. Perl est avant tout un langage de traitement de texte, et les expressions rationnelles sont au cur de ces fonctionnalits.

Expressions rgulires
Les expressions rgulires (aussi expressions rationnelles, regexps ou bien RE) sont utilises par la plupart des processeurs de texte du monde UNIX : grep et findstr, sed et awk,

customer_8566

Expressions rgulires

31

et les diteurs tels vi et emacs. Une expression rgulire est lcriture concise dun ensemble de chanes.23 La plupart des autres langages intgrent aussi le traitement des RE, mais aucun deux ne le fait la manire de Perl. Les expressions rationnelles sont employes de plusieurs manires dans Perl. Elles sont utilises en premier lieu dans des conditionnelles pour dterminer si une chane correspond un motif donn. Quand on voit quelque chose qui ressemble /machin/, on sait quil sagit dun oprateur de recherche de correspondance ordinaire.
if (/Windows 95/) { print "Il est temps de faire une mise jour ?\n" }

Ensuite, si lon peut retrouver des motifs dans une chane, on peut les remplacer par quelque chose dautre. Par exemple, s/machin/bidule/ demande de substituer bidule machin , si cela est possible. Nous appelons cela loprateur de substitution. Une RE peut aussi svaluer en un boolen, mais cest leffet de bord qui est utilis la plupart du temps.
s/Windows/Linux/;

Enfin, les motifs peuvent non seulement spcifier lemplacement de quelque chose, mais galement les endroits o il ne se trouve pas. Loprateur split emploie donc une expression rationnelle pour spcifier les emplacements do les donnes sont absentes. Autrement dit, lexpression rationnelle dfinit les dlimiteurs qui sparent les champs de donnes. Notre exemple de notation en comporte quelques exemples simples. Les lignes 5 et 12 clatent les chanes sur le caractre espace pour renvoyer une liste de mots. Mais split permet dclater sur tout dlimiteur spcifi par une expression rationnelle.
($bon, $brute, $truand) = split(/,/, "vi,emacs,teco");

Il existe de nombreux modificateurs utilisables dans chacun de ces contextes pour faire des choses plus exotiques comme lindiffrenciation des majuscules et des minuscules en recherchant des chanes de caractres, mais ce sont l des dtails que nous couvrirons au chapitre suivant. Lusage le plus simple des expressions rationnelles consiste rechercher une expression littrale. Dans le cas des clatements que nous venons de mentionner, nous avons recherch un simple espace. Mais si lon recherche plusieurs caractres la fois, ils doivent tous correspondre en squence. Cest--dire que le motif correspond une sous-chane, comme lon peut sy attendre. Admettons que nous dsirions montrer toutes les lignes dun fichier HTML reprsentant des liens vers dautres fichiers HTML (en excluant les liens FTP). Imaginons que nous travaillions en HTML pour la premire fois et que nous soyons donc un peu nafs. Nous savons que ces liens contiendront toujours la chane http: . Nous pouvons boucler dans le fichier comme ceci :24

23. Une bonne introduction est le livre de Jeffrey Friedl, Matrise des expressions rgulires (ditions OReilly). 24. Cela ressemble beaucoup la commande UNIX grep http: fichier. Sous MS-DOS, il est possible demployer la commande find, mais elle ne sait pas traiter dexpression plus complexe. (Cependant, le programme improprement nomm findstr de Windows NT comprend les expressions rationnelles.)

customer_8566

32
while ($ligne = <FICHIER>) { if ($ligne =~ /http:/) { print $ligne; } }

Chapitre 1 Vue densemble

Ici, le =~ (oprateur de liaison de motif) indique Perl quil doit rechercher lexpression rationnelle http: dans la variable $ligne. Sil trouve lexpression, loprateur renvoie une valeur vraie et le bloc (une commande daffichage) est excut. Au fait, si lon nutilise pas loprateur de liaison =~, Perl recherchera un motif par dfaut au lieu de $ligne. Ce motif par dfaut nest en fait quune variable spciale qui prend le nom curieux de $_. En fait, de nombreux oprateurs emploient la variable $_ et un expert de la programmation Perl peut crire ce qui prcde comme :
while (<FICHIER>) { print if /http:/; }

(Hmm, un autre modificateur dinstruction semble tre apparu ici. Insidieuses bestioles...) Tout cela est bien pratique, mais si nous voulons trouver tous les liens, et non les seuls HTTP ? Nous pouvons en donner une liste comme http: , ftp: , mailto: , etc. Mais cette liste peut tre longue, et que faire si un nouveau type de lien est ajout ?
while (<FILE>) { print if /http:/; print if /ftp:/; print if /mailto:/; # Et aprs? }

Comme les expressions rationnelles dcrivent un ensemble de chanes, nous pouvons nous contenter de dcrire ce que nous cherchons : un certain nombre de caractres alphabtiques suivis dun deux-points. Dans le dialecte des expressions rationnelles (le regexpais ?), ce serait /[a-zA-Z]+:/, o les crochets dfinissent une classe de caractres. Les a-z et A-Z reprsentent tous les caractres alphabtiques (le tiret reprsentant lintervalle de caractres entre le caractre de dbut et celui de fin, inclus). Et le + est un caractre spcial disant un ou plusieurs exemplaires du machin qui se trouve avant moi . Il sagit dun quantificateur, qui indique combien de fois quelque chose peut tre rpt. (Les barres obliques ne font pas vraiment partie de lexpression rationnelle, mais plutt de loprateur de correspondance. Elles nagissent que comme dlimiteurs de lexpression rationnelle). Certaines classes, comme la classe alphabtique, tant frquemment utilises, Perl dfinit des cas spciaux, qui comprennent :
Nom espace Caractre de mot Chiffre (digit) Dfinition ASCII [ \t\n\r\f] [a-zA-Z_0-9] [0-9] Caractre \s \w \d

customer_8566

Expressions rgulires

33

Remarquez quils ne correspondent qu des caractres simples. Un \w recherchera un unique caractre de mot et non un mot complet. (Vous souvenez-vous du quantificateur + ? On peut crire \w+ pour rechercher un mot.) Perl fournit galement la ngation de ces classes en employant le caractre en majuscule, comme \D pour un caractre qui nest pas un chiffre. (Il faut remarquer que \w nest pas toujours quivalent [a-zA-Z_0-9]. Certains locales dfinissent des caractres alphabtiques supplmentaires hors de la squence ASCII, et \w les respecte.)25 Certaines langues dfinissent des caractres alphabtiques au-del de la squence ASCII classique. Le code \w les prend en compte. Les rcentes versions de Perl connaissent aussi le codage UNICODE avec les proprits numriques et Perl traite ce codage avec les proprits en consquence. (Il considre aussi les idogrammes comme des caractres \w.) Il existe une autre classe de caractres trs spciale, que lon crit . , qui recherchera tout caractre.26 Par exemple, /a./ trouve toute chane contenant un a qui nest pas le dernier caractre de la chane. Il trouvera donc at ou am , ou mme a+ , mais non a puisquil ny a rien aprs le a qui puisse correspondre au point. Comme il cherche le motif nimporte o dans la chane, il le trouvera dans oasis et dans chameau , mais non dans sheba . Il trouvera le premier a de caravane . Il pourrait trouver le deuxime, mais il sarrte aprs la premire correspondance en cherchant de gauche droite.

Quantificateurs
Les caractres et les classes de caractres dont nous avons parl recherchent des caractres uniques. Nous avons dj mentionn que lon pouvait rechercher plusieurs caractres de mot avec \w+ pour correspondre un mot complet. Le + est un de ces quantificateurs, mais il y en a dautres (tous sont placs aprs llment quantifi). La forme la plus gnrale de quantificateur spcifie le nombre minimal et le nombre maximal de fois auquel un lment peut correspondre. Les deux nombres sont mis entre accolades, spars par une virgule. Par exemple, pour essayer de trouver les numros de tlphone dAmrique du Nord, /\d{7,11}/ rechercherait au moins 7 chiffres, mais au plus 11 chiffres. Si un seul chiffre se trouve entre les accolades, il spcifie la fois le minimum et le maximum ; cest--dire que le nombre spcifie le nombre exact de fois que llment peut tre rpt. (Si lon y rf lchit, tous les lments non quantifis ont un quantificateur implicite {1}.) Si lon met le minimum et la virgule en omettant le maximum, ce dernier passe linfini. En dautres termes, le quantificateur indique le nombre minimum de caractres, et tout ceux quil trouvera aprs cela. Par exemple, /\d{7}/ ne trouvera quun numro de tlphone local (dAmrique du Nord, sept chiffres), alors que /\d{7,}/ correspondra tous les numros de tlphones, mme les internationaux (sauf ceux qui comportent moins de 7 chiffres). Il nexiste pas de faon spcifique dcrire au plus un certain nombre de caractres. Il suffit dcrire, par exemple, /.{0,5}/ pour trouver au plus cinq caractres quelconques.
25. Ce qui est bien pratique pour rechercher les caractres accentus en franais. (N.d.T.) 26. Mais il ne trouvera pas un saut de ligne. Quand on y pense, un . ne correspond pas non plus un saut de ligne dans grep(1).

customer_8566

34

Chapitre 1 Vue densemble

Certaines combinaisons de minimum et de maximum apparaissant frquemment, Perl dfinit des quantificateurs spciaux. Nous avons dj vu +, qui est identique {1,}, cest--dire au moins une occurrence de llment qui prcde . Il existe aussi *, qui est identique {0,}, ou zro occurrence ou plus de llment qui prcde , et ?, identique {0,1}, ou zro ou une occurrence de llment qui prcde (llment qui prcde est donc optionnel). Il faut savoir deux ou trois choses concernant la quantification. Dabord, les expressions rationnelles de Perl sont, par dfaut, avides. Cela signifie quelles essayent de trouver une correspondance tant que lexpression entire correspond toujours. Par exemple, si lon compare /\d+ 1234567890 , cela correspondra la chane entire. Il faut donc spcialement surveiller lemploi de . , tout caractre. On trouve souvent une chane comme :
larry:JYHtPh0./NJTU:100:10:Larry Wall:/home/larry:/bin/tcsh

o on essaye de trouver larry avec /.+:/. Cependant, comme les expressions rationnelles sont avides, ce motif correspond tout ce qui se trouve jusqu /home/larry inclus. On peut parfois viter ce comportement en utilisant une ngation de classe de caractres, par exemple avec /[\^:]+:/, qui indique de rechercher un ou plusieurs caractres non-deux-points (autant que possible), jusquau premier deux-points. Cest le petit chapeau qui inverse le sens de la classe de caractres.27 Lautre point surveiller est que les expressions rationnelles essayent de trouver une correspondance ds que possible. Ce point est mme plus important que lavidit. Le balayage se produisant de gauche droite, cela veut dire que le motif cherchera la correspondance la plus gauche possible, mme sil existe un autre endroit permettant une correspondance plus longue (les expressions rationnelles sont avides, mais elles voient court terme). Par exemple, supposons que lon utilise la commande de substitution s/// sur la chane par dfaut ( savoir la variable $_), et que lon veuille enlever une suite de x du milieu de la chane. Si lon crit :
$_ = "fred xxxxxxx barney"; s/x*//;

cela naura aucun effet. En effet, le x* (voulant dire zro caractres x ou plus) trouvera le rien au dbut de la chane, puisque la chane nulle est large de zro caractres et que lon trouve une chane nulle juste avant le f de fred .28 Encore une chose savoir. Par dfaut, les quantificateurs sappliquent un caractre unique les prcdant, ce qui fait que /bam{2}/ correspond bamm mais pas bambam . Pour appliquer un quantificateur plus dun caractre, utilisez les parenthses. Il faut employer le motif /(bam){2}/ pour trouver bambam .

Correspondance minimale
Si lon ne voulait pas de correspondances avides dans les anciennes versions de Perl, il fallait employer la ngation dune classe de caractres (et en fait, on obtenait encore une correspondance avide, bien que restreinte).
27. Dsol, nous navons pas invent cette notation, ne nous en voulez pas. Il sagit simplement de la faon dcrire les expressions rationnelles dans la culture UNIX. 28. Mme les auteurs sy font prendre de temps en temps.

customer_8566

Expressions rgulires

35

Les versions modernes de Perl permettent de forcer une correspondance minimale par lemploi dun point dinterrogation aprs tout quantificateur. Notre recherche de nom dutilisateur serait alors /.*?:/. Ce .*? essaye alors de correspondre aussi peu de caractres que possible, au lieu dautant que possible, et il sarrte donc au premier deuxpoints au lieu du dernier.

Pour enfoncer le clou


Chaque fois que lon cherche faire correspondre un motif, celui-ci essayera partout jusqu ce quil trouve une correspondance. Une ancre permet de restreindre lespace de recherche. Une ancre est dabord quelque chose qui ne correspond rien , mais il sagit l dun rien dun type spcial qui dpend de son environnement. On peut aussi lappeler une rgle, une contrainte ou une assertion. Quelle que soit son appellation, elle essaie de faire correspondre quelque chose de longueur zro, et russit ou choue. (En cas dchec, cela veut surtout dire que le motif ne trouve pas de correspondance de cette faon. Il essaie alors dune autre manire, sil en existe.) La chane de caractres spciale \b correspond une limite de mot, qui est dfinie comme le rien entre un caractre de mot (\w) et un caractre de non-mot (\W), dans le dsordre. (Les caractres qui nexistent pas de part et dautre de la chane sont appels des caractres de non-mot). Par exemple,
/\bFred\b/

correspond Le Grand Fred et Fred le Grand , mais ne correspond pas Frederic le Grand parce que le de de Frederic ne contient pas de limite de mot. Dans une veine similaire, il existe galement des ancres pour le dbut et la fin dune chane. Sil sagit du premier caractre dun motif, le chapeau (^) correspond au rien au dbut de la chane. Le motif /^Fred/ correspondrait donc Frederic le Grand et non Le Grand Fred , alors que /Fred^/ ne correspondrait aucun des deux (et ne correspondrait dailleurs pas grand-chose). Le signe dollar ($) fonctionne comme le chapeau, mais il correspond au rien la fin de la chane au lieu du dbut.29 Vous devez maintenant tre en mesure de deviner ce que veut dire :
next LIGNE if /^#/;

Cest bien sr Aller la prochaine itration de la boucle LIGNE si cette ligne commence par un caractre # . Nous avons dit plus haut que la squence \d{7,11} concide avec un nombre de 7 11 chiffres de long ce qui est vrai mais incomplet: quand cette squence est utilise dans une expression comme /\d{7,11}/, a nexclue pas dautres chiffres aprs les 11 premiers. Donc, le plus souvent, lorsque vous utilisez des quantificateurs, vous utiliserez des ancres de chaque ct.

29. Tout ceci est un peu simpliste, car nous supposons ici que la chane ne contient quune ligne. ^ et $ sont en fait des ancres au dbut et en fin de ligne et non pas de chane. Nous essaierons de clarifier tout cela au chapitre 5, Recherche de motif (pour autant que lon puisse clarifier tout cela).

customer_8566

36

Chapitre 1 Vue densemble

Rfrences arrires
Nous avons dj mentionn que lon pouvait employer des parenthses pour grouper des caractres devant un quantificateur, mais elles peuvent aussi servir se souvenir de parties de ce qui a t trouv. Une paire de parenthses autour dune partie dexpression rationnelle permet de se souvenir de ce qui a t trouv pour une utilisation future. Cela ne change pas le motif de recherche, et /\d+ et /(\d+)/ chercheront toujours autant de chiffres que possibles, mais dans le dernier cas, ceux-ci seront mmoriss dans une variable spciale pour tre rfrencs en arrire plus tard. La faon de rfrencer la partie mmorise de la chane dpend de lendroit do on opre. Dans la mme expression rationnelle, on utilise un antislash suivi dun entier. Il correspond une paire de parenthses donne, dtermine en comptant les parenthses gauches depuis la gauche du motif, en commenant par un. Par exemple, pour rechercher quelque chose ressemblant une balise HTML (comme <B>Gras</B> ), on peut utiliser /<(.*?)>.*?<\/\1>/. On force alors les deux parties du motif correspondre exactement la mme chane de caractres, comme au B ci-dessus. Hormis lexpression rationnelle elle-mme, comme dans la partie de remplacement dune substitution, la variable spciale est utilise comme sil sagissait dune variable scalaire normale nomme par lentier. Donc, si lon veut changer les deux premiers mots dune chane, par exemple, on peut employer :
s/(\S+)\s+(\S+)/$2 $1/

Le ct droit de la substitution quivaut une sorte de chane protge par des apostrophes doubles, ce qui explique pourquoi lon peut y interpoler des variables, y compris des rfrences arrires. Ce concept est puissant : linterpolation (sous contrle) est une des raisons pour lesquelles Perl est un bon langage de traitement de texte. Entre autres raisons, on trouve bien entendu les motifs de correspondance. Les expressions rationnelles savent parfaitement extraire des lments et linterpolation sert les rassembler. Peut-tre existe-t-il enfin un espoir pour Humpty Dumpty.

Traitement des listes


Nous avons vu plus haut que Perl connat deux principaux contextes, le contexte scalaire (pour grer les singularits) et le contexte de liste (pour grer les pluralits). La plupart des oprateurs traditionnels que nous avons dcrits jusquici taient strictement scalaires dans leur opration. Ils prennent toujours des arguments singuliers (ou des paires darguments singuliers pour les oprateurs binaires), et produisent toujours un rsultat singulier, mme dans un contexte de liste. Donc, si lon crit ceci :
@tableau = (1 + 2, 3 - 4, 5 * 6, 7 / 8);

on sait que la liste de droite contient exactement quatre valeurs, car les oprateurs mathmatiques ordinaires produisent toujours des valeurs scalaires, mme dans le contexte de liste fourni par lassignation un tableau. Cependant, dautres oprateurs Perl peuvent produire soit un scalaire, soit une liste, selon le contexte. Ils savent si vous attendez deux un scalaire ou une liste. Mais comment pouvez-vous le savoir ? Cest en fait trs simple une fois que vous vous tes familiariss avec quelques concepts clefs.

customer_8566

Traitement des listes

37

Premirement, le contexte de liste doit tre fourni par quelque chose dans l environnement . Dans lexemple ci-dessus, cest lassignation de liste qui le fournit. Nous avons vu ci-avant que la liste dans linstruction de boucle foreach fournit le contexte de liste. Loprateur print aussi. Il est possible de tous les identifier dun coup. Si vous regardez les nombreuses reprsentations syntaxiques des oprateurs dans le reste de ce livre, divers oprateurs sont dfinis pour prendre une LISTE en argument. Ce sont les oprateurs qui fournissent un contexte de liste. Tout au long de ce livre, LISTE est employ comme le terme technique signifiant une construction syntaxique fournissant un contexte de liste . Par exemple, si lon regarde sort, on trouve le rsum de syntaxe suivant :
sort LISTE

Ce qui veut dire que sort procure un contexte de liste ses arguments. Deuximement, la compilation, tout oprateur qui prend une LISTE fournit un contexte de liste chaque lment syntaxique de cette LISTE. Chaque oprateur ou entit de haut niveau de la LISTE sait quil est cens fournir la meilleure liste possible. Cela signifie que si lon crit :
sort @mecs, @nanas, autres();

@mecs, @nanas et autres() savent tous quils sont censs fournir une valeur de liste. Enfin, lexcution, chacun de ces lments de LISTE fournit sa liste, puis (ceci est important) toutes les listes isoles sont rassembles, bout bout, en une liste unique. Et cette liste unique, unidimensionnelle, est ce qui est finalement donn la fonction qui voulait une LISTE. Si donc @mecs contient (Fred, Barney), @nanas contient (Wilma, Betty), et que la fonction autre() renvoie la liste un seul lment (Dino), la LISTE que voit sort devient :
(Fred,Barney,Wilma,Betty,Dino)

et sort renvoie la liste :


(Barney,Betty,Dino,Fred,Wilma)

Certains oprateurs produisent des listes (comme keys), certains les consomment (comme print) et dautres les transforment en dautres listes (comme sort). Les oprateurs de cette dernire catgorie sont considrs comme des filtres ; mais contrairement au shell, le f lux de donnes seffectue de droite vers la gauche, puisque les oprateurs de liste agissent sur les lments qui sont passs leur droite. On peut empiler plusieurs oprateurs de liste la fois :
print reverse sort map {lc} keys %hash;

Toutes les clefs de %hash sont prises et renvoyes la fonction map, qui met chacune dentre elles en minuscule par loprateur lc, et les passe la fonction sort qui les trie et les repasse la fonction reverse, qui renverse lordre des lments de la liste, qui les passe enfin la fonction print, qui les affiche. Cest, on le voit, beaucoup plus facile dcrire en Perl quen franais. Nous ne pouvons lister tous les exemples o lutilisation de la structure de liste produit un code plus naturel lire. Mais revenons sur les RE un moment. Dans un contexte de liste, toutes les concidences sont mmorises dans les lments successifs de la liste. Cherchons, par exemple, toutes les chanes de la forme 12:59:59 am . On peut le faire comme ceci :

customer_8566

38

Chapitre 1 Vue densemble


($hour, $min, $sec, $ampm) = /(\d+):(\d+):(\d+) *(\w+)/;

Ce qui est une faon pratique dinstancier plusieurs variables en mme temps. On peut aussi crire :
@hmsa = /(\d+):(\d+):(\d+) *(\w+)/;

et mettre ces 4 valeurs dans un tableau. trangement, par la sparation de laction entre les RE et les expressions Perl, le contexte de liste augmente les possibilits du langage. Nous ne le voyons pas, mais Perl est un vritable langage orthogonal en plus dtre diagonal. Allez, on fait une pause !

Ce que vous ne savez pas ne vous fera pas (trop) de mal


Enfin, permettez-nous de revenir encore une fois au concept de Perl en tant que langage naturel. Les usagers dun langage naturel ont le droit davoir des niveaux daptitude diffrents, de parler diffrents sous-ensembles de ce langage, dapprendre au fur et mesure et, en gnral, de lutiliser avant den connatre toutes les arcanes. Vous ne connaissez pas tout de Perl, tout comme vous ne connaissez pas tout du franais. Mais ceci est Officiellement OK dans la culture Perl. Vous pouvez employer utilement Perl mme si nous ne vous avons pas encore appris crire vos propres sous-programmes. Nous avons peine commenc expliquer que Perl pouvait tre vu comme un langage de gestion systme, ou comme un langage de prototypage rapide, ou comme un langage rseau, ou comme un langage orient objet. Nous pourrions crire des chapitres entiers sur ces sujets (et vrai dire, cest dj le cas). Mais au bout du compte, vous devrez crer votre propre vision de Perl. Cest votre privilge, en tant quartiste, de vous inf liger vous-mme la douleur de la crativit. Nous pouvons vous apprendre notre faon de peindre, mais nous ne pouvons pas vous apprendre votre faon. TMTOWTDI : il existe plus dune faon de faire. Amusez-vous comme il convient.

customer_8566

Sance de dissection

II

customer_8566

customer_8566

Composants de Perl

O nous tudions les lments de lensemble. Dans les prochains chapitres nous progresserons du particulier vers le gnral, approche ascendante, en commenant par dcrire les composants lmentaires qui permettront daborder les structures plus labores, un peu la manire dont les atomes forment les molcules. Linconvnient est que vous nen aurez pas ncessairement une image globale sans auparavant avoir t submerg par de nombreux dtails, mais lavantage est que vous comprendrez les exemples au fur et mesure. (si vous prfrez lapproche inverse, retournez le livre et lisez ce chapitre lenvers). Chaque chapitre est construit sur le prcdent ce qui ncessite une lecture linaire, (vous devrez donc faire attention si vous tes du genre sautiller dune page lautre). Vous tes invit utiliser les diffrentes annexes la fin du livre. (Ce qui nest pas du sautillement.) Chaque mot distingu par une police type se trouve au chapitre 29, Fonctions. Bien que nous avons essay de ne pas privilgier un systme dexploitation, si vous tes peu au courant de la terminologie Unix et si vous rencontrez un mot qui semble dire autre chose que ce que vous pensez, reportez-vous au glossaire. Si cela ne marche pas, essayez lindex.

Atomes
Le plus petit lment visible du langage est le caractre, celui que lon peut visualiser dans un diteur par exemple. Au dpart, Perl ne faisait pas la distinction entre octets et caractres ASCII, mais pour des raisons dinternationalisation, il faut bien distinguer les deux. Le code Perl peut tre crit exclusivement en ASCII, mais autorise aussi lutilisation dun codage sur 8 ou 16 bits, quil soit celui dune langue ou bien de tout autre codage dfini rgulirement, condition de le faire dans des chanes litrales uniquement. Bien sr, Perl ne vrifiera pas le contenu du texte mais saura simplement quun caractre est cod sur 16 bits.

customer_8566

42

Chapitre 2 Composants de Perl

Comme expliqu au chapitre 15, Unicode, Perl implmente Unicode.1 Cest transparent pour lutilisateur du langage qui peut en utiliser aussi bien dans des identificateurs (noms de variables, etc) que dans des chanes litrales. Pour Perl, tous les caractres ont la mme taille de rfrence, par exemple 1, quelle que soit la reprsentation interne quil en fait ensuite. En principe, il code les caractres sous forme UTF-8 et donc un caractre peut avoir une forme interne sur 1, 2, 3... octets. (LUnicode smiley U-263A est une squence de 3 octets.) Mais poursuivons lanalogie physique un peu plus avant avec les atomes. Les caractres sont atomiques de la mme faon que les atomes codent les diffrents lments. Un caractre est compos de bits et doctets mais si on le dsintgre (dans un acclrateur de caractres, sans doute), il perd toutes ses proprits propres. De la mme manire que les neutrons composent latome dUranium U-238, les octets qui composent le caractre smiley U-263A sont un dtail de son implmentation. Il faut donc bien distinguer le mot caractre du mot octet . Cest pourquoi on peut le prciser linterprteur avec la directive use bytes. (Voir le chapitre 31, Modules de pragmas). De toute manire, Perl saura par lui-mme faire le codage sur 8 bits quand il le faudra. Maintenant passons dans la prochaine dimension.

Molcules
Perl est un langage informel, ce qui ne veut pas dire quil na pas de forme, mais plutt dans le sens usuel du terme, cest--dire un langage quon peut crire avec des espaces, tabulations et caractres de nouvelle ligne partout o vous voulez sauf dans les units syntaxiques. Par dfinition, un symbole ne contient pas despace. Un symbole est une unit syntaxique avec un sens pour linterprteur, comme pour un mot dans une phrase, mais qui peut contenir dautres caractres que des lettres tant que cette unit nest pas rompue. (Ce sont de vraies molcules qui peuvent utiliser toutes sortes datomes. Par exemple, les nombres et les oprateurs mathmatiques sont des symboles. Un identificateur est un symbole qui dbute par une lettre ou un soulign et qui ne contient que des lettres, chiffres ou souligns. Un symbole ne peut contenir despace puisque le caractre espace couperait le symbole en deux nouveaux symboles, tout comme un caractre espace, en franais couperait un mot en deux nouveaux mots.2 Bien que le caractre espace soit ncessaire entre deux symboles, les espaces ne sont obligatoires quentre deux symboles qui, sinon, seraient pris pour un seul. cet effet, tous les espaces sont quivalents. Un commentaire est compt comme un espace. Les sauts de ligne ne sont diffrents des espaces quentre des dlimiteurs, dans certains formats et pour des formes orientes ligne de protection. Plus prcisment le caractre de saut de ligne ne dlimite pas une instruction comme en FORTRAN ou en Python. Les instructions en Perl se terminent par le caractre ; comme en C.
1. Aussi enthousiaste que nous soyons au sujet dUnicode, la plupart de nos exemples sont en ASCII, tant donn que tout le monde na pas ncessairement un diteur de texte Unicode. 2. Dans les chanes litrales, cest le guillemet qui dlimite lunit et non lespace, on peut donc y inclure ce caractre.

customer_8566

Types internes

43

Les caractres despace Unicode sont autoriss dans un programme Perl Unicode moyennant certaines prcautions. Si vous utilisez les caractres spciaux Unicode sparateurs de paragraphe et de ligne, dune manire diffrente que ne le fait votre diteur de texte, les messages derreur seront plus difficile interprter. Cest mieux dutiliser les caractres de saut de ligne classiques. Les symboles sont dtects dune manire large ; linterprteur Perl lit le symbole le plus long possible lors de la lecture du code. Si vous voulez quil distingue deux symboles il suffit dinsrer un espace blanc entre eux. (La tendance est dinsrer plusieurs espaces pour rendre le code plus lisible.) Un commentaire commence par le caractre # et stend jusqu la fin de la ligne. Un commentaire quivaut un espace et joue le rle de sparateur. Perl ninterprte pas une ligne place en commentaire.3 Si une ligne, et cest une autre originalit lexicale, commence par = un endroit o une instruction serait lgale, Perl ignore tout de cette ligne jusqu la prochaine contenant =cut. Le texte ignor est suppos tre du POD, ou Plain Old Documentation (des programmes Perl permettent de convertir ces commentaires au format des pages de manuel, ou en documents L, HTML et bientt XML). Dune manire complmentaire, lanalyseur lexical extrait le code Perl dun module et ignore les balises pod, ce qui permet de conserver la documentation lintrieur des modules. Voir le chapitre 26, POD, pour les dtails sur pod et la documentation multiligne. Mais seul le premier # est ncesaire, les autres ne sont que de la dcoration, bien que la plupart des codeurs lutilisent pour faire des effets visuels comme avec le langage C ou ils font une utilisation abondante du caractre *. En Perl, comme en chimie ou en linguistique, on construit des structures de plus en complexes partir dlments simples. Par exemple, une instruction est une squence de symboles sur le mode impratif. On peut combiner une srie dinstructions pour former un bloc dlimit par des accolades. Les blocs peuvent eux-mmes constituer dautres blocs. Certains blocs fonctionnels tels que les sous-programmes peuvent tre combins en modules eux-mmes combins en programmes, nous verrons tout ceci dans les prochains chapitres. Mais crons encore des symboles avec nos caractres.

Types internes
Avant de construire des types plus complexes, nous devons introduire quelques abstractions, plus prcisment trois types de donnes. Chaque langage dispose de ses propres types de donnes et la diffrence des autres, Perl en possde peu ce qui rduit les confusions possibles. Prenons par exemple le langage C qui dispose des types suivants : char, short, int, long, long long, bool, wchar_t, size_t, off_t, regex_t, uid_t, u_longlong_t, pthread_key_t, fp_exception_field_type, et ainsi de suite. Ce sont juste les types entiers! Il y a ensuite les nombres f lottants, les pointeurs et les chanes.
3. En fait ce nest pas exact. Lanalyseur lexical de Perl regarde sil existe un slecteur du type #! (voir le chapitre 19, Linterface de la ligne de commande). Il peut aussi analyser les numros de ligne produits par diffrents prpocesseurs (voir la section Gnrer du Perl dans dautres langages au chapitre 24, Techniques couramment employes).

customer_8566

44

Chapitre 2 Composants de Perl

Tous ces types compliqus nen font quun en Perl : le scalaire. (Les types simples de donnes sont suffisants pour les besoins usuels, et il est possible de crer ses propres types en utilisant la programmation objet en Perl, voir le chapitre 12, Objets.) Les trois types de base en Perl sont : les scalaires, les tableaux de scalaires et les hachages de scalaires (connus aussi sous le nom de tableaux associatifs). On peut aussi les appeler structures de donnes. Les scalaires constituent le type fondamental partir duquel les structures plus complexes peuvent tre construites. Un scalaire peut contenir une seule valeur simple, typiquement une chane ou un nombre. Les lments de ce type simple peuvent tre combins lintrieur des deux autres types composs. Un tableau est une liste ordonne de scalaires accessibles par un indice numrique (les indices dmarrent zro). Contrairement aux autres langages, Perl traite les indices ngatifs en comptant partir de la fin du type index aussi bien des chanes que des listes. Un hachage est un ensemble non ordonn de paires clef/valeur accessibles par une clef de type chane utilise pour accder la valeur scalaire associe. Les variables ont toujours lun de ces trois types. ( part les variables, Perl comprend des bidules plus ou moins confidentiels tels que des handles de fichiers et de rpertoires, des sous-programmes, des typeglobs, des formats et des tables de symboles.) Laissons la thorie et passons la pratique du langage pour en voir les possibilits. Nous allons donc crire du code et pour cela vous prsenter les termes constituant les expressions en Perl rgies par des rgles syntaxiques. Nous utilisons la terminologie terme quand nous parlerons des units syntaxiques, un peu comme dans les quations mathmatiques. La fonction des termes en Perl est de fournir des valeurs pour des oprateurs tels laddition ou la multiplication. Mais la diffrence dune quation, Perl interprte lexpression dans une action logique de la machine. Une des actions les plus courantes est la sauvegarde dune valeur en mmoire :
$x = $y;

Cest un exemple de loprateur daffectation (non pas loprateur de test dgalit des valeurs numriques, ce qui scrit == en Perl). Laffectation prend la valeur de $y et la place dans la variable $x. Notez que le terme $x nest pas utilis pour sa valeur mais pour sa fonction de mmorisation. (Lancienne valeur de $x disparat avec laffectation.) Nous disons que $x est une lvalue, parce quelle est cible dune affectation gauche dune expression. Et nous disons que $y est une rvalue car droite dans ce type dexpression. Il y a un troisime type de valeur appele temporaire quil est ncessaire de comprendre. Considrons lexpression simple suivante :
$x = $y + 1;

Perl prend la rvalue $y et lui ajoute la rvalue 1, ce qui produit une valeur temporaire qui est ensuite affecte la lvalue $x. Ces valeurs temporaires sont places dans une structure interne appele pile.4

4. Une pile fonctionne la manire de ces piles dassiettes dans les restaurants on peut empiler (push) ou bien dpiler (pop) une assiette (le push et le pop tant deux termes bien tablis dans la science informatique)

customer_8566

Variables

45

Les termes dune expression empilent des valeurs, alors que ses oprateurs (dont nous parlerons dans le prochain chapitre) dpilent des valeurs et peuvent aussi empiler des rsultats pour le prochain oprateur. Dans la pile, une expression produit autant de valeurs quelle en consomme. Nous reviendrons sur les valeurs temporaires. Certains termes sont exclusivement des rvalues comme 1, certains autres peuvent jouer les deux rles, comme la variable de lexemple prcdent nous la montr. Cest ce que nous allons voir dans la prochaine section.

Variables
Il y existe trois types de variables correspondant aux trois types abstraits mentionns plus haut. Chacun deux est prfix par un caractre spcial.5 Les variables scalaires sont toujours dfinies avec un caractre $ initial, mme si elles font rfrence des scalaires lintrieur dun tableau ou dun hachage. Ce caractre fonctionne un peu comme larticle dfini singulier (le ou la). Nous avons donc :
Construction $jours $jours[28] $jours{Fev} Signification Valeur scalaire simple $jours. 29e lment du tableau @jours. Valeur Fev du hachage %jours.

Noter que vous pouvez utiliser le mme nom pour $jours, @jours, et %jours, Perl ne les confondra pas. Il existe dautres caractres spciaux qui sappliquent sur les scalaires et sont utiliss dans des cas prcis. Ils ressemblent ceci :
Construction ${jours} $Calendrier::jours $#jours $jours->[28] $jours[0][2] $jours{2000}{Fev} $jours{2000,Fev} Signification Identique $jours en levant lambigut devant les caractres alphanumriques. Une autre variable $jours, dans le paquetage Calendrier. Dernier index du tableau @jours. 29e lment du tableau point par la rfrence $jours. Tableau multidimensionnel. Hachage multidimensionnel. mulation de hachage multidimensionnel.

Les tableaux ou les tranches de tableaux (ainsi que les tranches de hachage) dbutent par le caractre @, qui fonctionne un peu comme larticle dfini pluriel (les) :

5. Encore des termes couramment usits en informatique

customer_8566

46
Construction @jours @jours[3,4,5] @jours[3..5] @jours{jan,fev} Signification

Chapitre 2 Composants de Perl

quivaut ($jours[0], $jours[1],... $jours[n]). quivaut ($jours[3], $jours[4], $jours[5]). quivaut @jours[3,4,5]. quivaut ($jours{jan}, $jours{fev}).

Les hachages dbutent par % :


Construction %jours Signification @(jan => 31, fev => $bissextil e? 29: 28, ...) .

Chacun de ces neuf exemples peut servir de lvalue, cest--dire quils spcifient une adresse laquelle on peut, en autres choses, loger une valeur. Avec les tableaux, les hachages et les tranches de tableaux ou de hachages, la lvalue fournit un moyen simple daffecter plusieurs valeurs dun seul coup :
@days = 1 .. 7;

Noms
Nous avons parl de variables pour mmoriser des valeurs mais il faut aussi mmoriser les noms et dfinitions de ces variables. En thorie, cela sappelle des espaces de nommage. Perl dispose de deux sortes despaces de nommages : la table des symboles et les portes lexicales.6 Il peut y avoir un nombre quelconque de tables et de portes lexicales et lintersection des deux ensembles est nulle, pour chaque instance de linterprteur Perl. Nous dtaillerons chacun de ces types tout au long de cet ouvrage. Disons simplement pour le moment que les tables de symboles sont des hachages porte globale qui contiennent la table des symboles des variables globales (y compris les hachages des autres tables de symboles). A contrario, les portes lexicales sont des espaces anonymes non inclus dans une table, mais lis un bloc de code du programme courant. Ils contiennent des variables accessibles uniquement dans le bloc en cours. (Cest pourquoi on utilise le terme porte.) Le mot lexical veut dire relatif au bloc de texte courant (ce qui na rien voir avec ce quun lexicographe entend par l. Ne vous fchez pas.). Dans chaque espace de nommage, global ou lexical, chaque type de variable dispose de son propre sous-espace de nommage dtermin par le caractre spcial affect au type. Il est possible, sans risque de conf lit, dutiliser le mme nom pour une variable scalaire, un tableau ou un hachage (ou encore, pour un handle de fichier, un nom de sous-programme, un label ou votre lama familier). Cela signifie que $machin et @machin sont deux variables diffrentes. Cela veut aussi dire que $machin[1] est un lment de @machin et non une partie de $machin. Bizarre, vous avez dit bizarre ? Mais cest normal, bizarrement.
6. On les appelle plutt paquetages et pads quand il sagit de limplmentation spcifique de Perl, mais les expressions rallonge sont les termes gnriques utiliss dans lindustrie du logiciel, et nous les utiliserons donc. Dsol.

customer_8566

Noms

47

Pour lappel dun sous-programme le caractre & est facultatif. Gnralement un nom de sous-programme nest pas une lvalue, quoique dans les versions rcentes de Perl un sous-programme peut svaluer une lvalue de telle sorte que lon peut lui affecter une valeur en retour. Parfois on veut accder aux variables dun symbole donn, sym par exemple. Il suffit dutiliser le caractre spcial * o lastrisque indique tout type de variable (scalaire, tableau, hachage). On les appelle typeglobs ; ils ont plusieurs fonctions. Ils peuvent tre utiliss comme lvalues. Limportation des modules se fait par laffectation des typeglobs. Nous reviendrons sur ce thme plus tard. Perl, comme tout langage informatique, dispose dune liste de mots rservs quil reconnat comme termes spciaux. Cependant, les noms de variables commenant par un caractre spcial, il ny a pas de confusion possible avec les premiers. Dautres types de noms ne commencent pas par ces caractres : les descripteurs de fichiers et les tiquettes. Avec ceux-ci attention ne pas entrer en conf lit avec des mots rservs. Nous vous recommandons pour ces types, dutiliser des majuscules pour leurs noms. Par exemple, si vous crivez open(LOG, logfile) plutt que le regrettable open(log, "logfile"). Perl comprendra que vous ne parlez pas de la fonction log et des logarithmes,7 et prvient les futurs conf lits avec les nouvelles versions de Perl. Le nom des modules utilisateurs commence avec une majuscule alors que les modules pragmas prdfinis sont crits en minuscules. Quand nous aborderons la programmation oriente objet, vous verrez que les noms de classes sont en capitales pour la mme raison. Comme vous pouvez le dduire du prcdent paragraphe, la casse est importante dans les identificateurs TRUC, Truc, et truc sont trois noms diffrents en Perl. Un identificateur commence avec une lettre ou un soulign, il peut contenir des lettres et des chiffres, y compris les caractres Unicode, et peut avoir une longueur comprise entre 1 et 251 inclus. Les idogrammes Unicode sont des lettres mais nous vous dconseillons des les utiliser si vous ne savez pas les lire. Voir le chapitre 15. Les noms qui suivent ces caractres spciaux ne sont pas ncessairement des identificateurs. Ils peuvent commencer par un chiffre auquel cas lidentificateur ne peut contenir que des chiffres comme dans $123. Les noms qui commencent par tout autre caractre quune lettre, un chiffre ou soulign (comme $? ou $$), sont limits ce caractre et sont prdfinis en Perl. Par exemple $$ est lID du processus courant et $? est lindicateur dtat retourn par le dernier processus fils cr. Dans la version 5.6 de Perl est implmente une syntaxe extensible pour les noms de variable interne. Toute variable de la forme ${^NAME} est une variable spciale rserve par Perl. Tous ces noms spciaux sont dans la table principale de symboles. Voir le chapitre 28, Noms spciaux, pour les exemples. On pourrait penser que noms et identificateurs dsignent la mme chose, mais lorsquon parle de nom, cest du nom absolu quil sagit, cest--dire celui qui indique quelle table de symboles il appartient. De tels noms sont forms par une srie didentificateurs spars par le symbole :: :
$Doc::Aide::Perl::Classe::chameau
7. On applique ici un des principes de Perl qui prtend que des choses diffrentes doivent tre reprsentes diffremment, ce qui rend le code plus lisible ( comparer avec les langages qui obligent des choses diffrentes avoir la mme apparence, au dtriment de la lisibilit.

customer_8566

48

Chapitre 2 Composants de Perl

Ce qui fonctionne comme un nom absolu de fichier :


/Doc/Aide/Perl/Classe/chameau

En Perl, ce chemin absolu indique les tables de symboles imbriques, et le dernier identificateur est le nom de la variable elle-mme, contenu dans la dernire table imbrique. Par exemple, pour la variable de lexemple prcdent, la table de symbole se nomme Doc::Aide::Perl::Classe, et le nom de la variable dans cette table est $chameau. (la valeur de cette variable est bien entendu beige .) Une table de symboles en Perl se nomme aussi un paquetage. Donc ces variables sont aussi appeles variables de paquetage. Les variables de paquetage sont dites prives relativement leur paquetage, mais sont globales dans le sens o les paquetages sont euxmmes globaux, cest--dire quil suffit de nommer le paquetage pour y accder, ce qui est difficile faire par inadvertance. Par exemple, un programme qui rfrence $Doc::categorie demande la variable $categorie dans le paquetage Doc::, qui na rien voir avec la variable $Livre::categorie. Voir le chapitre 10, Paquetages. Les variables attaches une porte lexicale ne sont pas contenues dans un paquetage, et ne contiennent pas la squence ::. (Les variables porte lexicale sont dclares avec my.)

Recherche des noms


La question est donc comment Perl devine le chemin absolu dun nom ? Comment trouve-t-il par exemple le nom de $categorie ? Voici les tapes successives suivies par linterprteur Perl dans la phase de lecture du code, pour rsoudre les noms dans le contexte courant : 1. Premirement, Perl inspecte le bloc immdiatement contenant, pour une dclaration du type my (ou our) (Voir le chapitre 29, ainsi que la section Dclarations avec porte au chapitre 4, Instructions et dclarations). Sil trouve cette dclaration, alors la variable est porte lexicale et nexiste dans aucun elle existe uniquement dans le bloc courant. Une porte lexicale est anonyme et ne peut donc tre atteinte hors du bloc la contenant.8 2. Sil ne trouve pas, Perl cherche une variable porte lexicale dans le bloc contenant le prcdent et sil la trouve, il la marque comme appartenant ce bloc de niveau suprieur. noter que dans ce cas, sa porte comprend le bloc de la premire tape. Dans le cas inverse, il rpte cette deuxime tape jusqu la sortie du bloc racine, le plus grand contenant les prcdents. 3. Quand il ny a plus de blocs contenants, linterprteur examine lunit de compilation entire, ce qui peut tre le fichier entier ou la chane en cours de compilation dans le cas de lexpression eval CHAINE. Dans ce dernier cas, la porte lexicale est la chane elle-mme et non un bloc entre accolades. Si Perl ne trouve pas la variable
8. Si la dclaration our est utilise la place, cela revient dclarer un alias de variable de paquetage. Le code extrieur peut accder cette variable mais seulement par lintermdiaire du paquetage o la variable est dfinie. Pour le reste une dfinition our fonctionne exactement comme une dfinition my. Cest utile pour limiter lusage des globales avec la directive use strict (voir la directive strict au chapitre 31). Mais il est prfrable dutiliser my quand une variable globale nest pas ncessaire.

customer_8566

Noms

49

dans la porte lexicale de la chane, il considre quil ny a plus de bloc et retourne ltape 2 en partant de la porte lexicale du bloc eval STRING. 4. ce point, Perl na pas encore trouv de dclaration pour notre variable (ni my, ni our). Perl abandonne la recherche dune variable lexicale, et suppose que la variable recherche est une variable de paquetage. Le degr suivant de recherche est donc le paquetage. Si la directive strict est active, le compilateur provoque une erreur, (sauf si la variable est prdfinie ou importe dans le paquetage courant), car il ne peut exister de variable globale sans qualifiant. Il cherche la dclaration package toujours dans la porte lexicale, et sil la trouve, insre le nom du paquetage trouv au dbut de la variable. 5. Sil ne trouve pas de dclaration de paquetage dans la porte lexicale, Perl recherche la variable dans le paquetage main qui contient tous les autres. En labsence de dclaration contraire, $categorie veut dire $::categorie, qui veut dire $main::categorie. (main tant un paquetage dans le paquetage de plus haut niveau, cela veut aussi dire $::main::categorie ou encore $main::main::categorie et $::main::main::categorie et ainsi de suite. On en verra toute lutilit dans Tables de symboles au chapitre 10.) Il y a plusieurs consquences que nous devons souligner ici : Le fichier tant la plus grande porte lexicale, une variable porte lexicale ne peut tre vue en dehors du fichier dans lequel elle est dclare. Les portes de fichier ne sont pas imbriques. Tout code Perl compil appartient au moins une porte lexicale et exactement un paquetage. La porte obligatoire est le fichier de code lui-mme. Les blocs contenant dfinissent les portes successives. Tout code Perl est compil dans un paquetage exactement, et si la dclaration du paquetage a une porte lexicale, le paquetage nen a pas, il est global. Une variable sans qualifiant peut tre cherche dans diffrentes portes lexicales, mais dans un seul paquetage, qui est le paquetage actif (dtermin par la porte lexicale de la variable). Un nom de variable ne peut avoir quune porte. Bien que deux portes sont actives au mme moment (lexicale et paquetage), une variable ne peut exister que dans une seule la fois. Un nom de variable sans qualifiant ne peut exister que dans une place mmoire, soit dans la premire porte lexicale, soit dans le paquetage courant, mais pas les deux. La recherche sarrte ds que la place mmoire est trouve, et les autres places mmoire qui auraient t trouves si la recherche stait poursuivie, ces places mmoire donc sont nanmoins inaccessibles. La place mmoire dune variable typique peut tre compltement dtermine la compilation.

Maintenant on sait comment le compilateur Perl rsoud les noms, mais parfois on ne connat pas ce nom au moment de la compilation : par exemple dans le cas dune indirection. Dans ce cas, Perl fournit un mcanisme qui permet de remplacer une variable par une expression qui retourne une rfrence cette variable. Par exemple, au lieu de dire :

customer_8566

50
$categorie

Chapitre 2 Composants de Perl

vous diriez :
${ une_expression() }

et si la fonction une_expression() retourne une rfrence la variable $categorie (ou bien la chane "categorie"), cela fonctionne de la mme manire. Par contre, si la fonction retourne $thesaurus ce sera cette variable la place. Cette syntaxe est la plus gnrale (et la moins lisible) des formes dindirection, mais nous verrons des variantes plus pratiques au chapitre 8, Rfrences.

Valeurs scalaires
Quil soit rfrenc directement ou indirectement, dans une variable, un tableau ou bien une variable temporaire, un scalaire contient toujours une valeur simple qui peut tre un nombre, une chane ou une rfrence une autre donne. Il peut aussi navoir aucune valeur auquel cas il est dit indfini. Les scalaires sont sans type, mme sils peuvent rfrencer toutes sortes de donnes : il nest pas ncessaire de les dclarer.9 Perl mmorise les chanes comme des squences de caractres sans contrainte de longueur ni de contenu. Nul besoin de dclarer une taille lavance et tout caractre peut y tre inclus, y compris le caractre nul. Les nombres sont reprsents sous forme dentiers signs si possible, ou bien sous forme de nombres virgule f lottante en double prcision dans le format natif de la machine. Les valeurs f lottantes ne sont pas infiniment prcises, cest pourquoi certaines comparaisons de la forme (10/3 == 1/3*10) chouent mystrieusement. Perl convertit les scalaires en diffrents sous-types suivant les besoins ; le numrique peut tre trait comme du caractre et inversement, Perl faisant Ce Quil Faut. Pour convertir du caractre en numrique, Perl utilise la fonction C atof(3). Pour passer du numrique une chane de caractres, il fait lquivalent de sprintf(3) avec le format "%.14g" sur la plupart des machines. La conversion dune chane non numrique comme truc convertit le literal la valeur 0 ; sils sont actifs, les avertissements sont affichs sinon rien. Voir le chapitre 5, pour des exemples permettant didentifier le contenu dun chane. Alors que les chanes de caractres et les numriques sont interchangeables dans peu prs tous les cas, les rfrences sont dun genre diffrent. Elles sont fortement types, ce sont des pointeurs non convertibles (transtypables) comprenant des compteurs de rfrences et des invocations de destructeurs internes. Ils sont utilisables pour crer des types de donnes complexes, incluant vos propres objets. Ceci dit, les rfrences restent des scalaires, car ce qui importe nest pas tant la compexit dune structure que le fait de la considrer comme un simple scalaire. Par non convertibles, nous voulons dire que lon ne peut pas, par exemple, convertir une
9. Les versions futures de Perl permettront de dclarer les trois types int, num et str, pour lever toute ambiguit pour loptimiseur de code. Ces types seront utiliss dans du code critique qui doit sexcuter rapidement, et nous nentrerons pas dans le dtail maintenant. Le mcanisme de pseudo-hash utilise ces types optionels la manire dun langage plus fortement typ. Voir le chapitre 8 pour aller plus loin.

customer_8566

Valeurs scalaires

51

rfrence de tableau en une rfrence de hachage. Les rfrences ne sont pas convertibles en un autre type pointeur. Cependant, en utilisant une rfrence en numrique ou en caractre, on obtient une valeur numrique ou une chane de caractres, ce qui permet de se souvenir du caractre unique dune rfrence, mme si le rfrencement de la valeur est perdu au cours de la copie depuis la vraie rfrence. On peut comparer diffrentes rfrences ou tester si elles sont dfinies. Mais on ne peut en faire beaucoup plus puisquil nexiste pas de moyen de convertir du numrique ou du caractre en rfrence. En principe, si Perl noblige pas faire de larithmtique de pointeurs ou carrment linterdit , ce nest pas un problme. Voir le chapitre 8 pour en connatre plus sur les rfrences.

Littraux numriques
Les littraux numriques sont spcifis par nimporte quel format courant10 de virgule f lottante ou dentier :
$x $x $x $x $x $x $x = = = = = = = 12345; 12345.67; 6.02E23; 4_294_967_296; 0377; 0xffff; 0b1100_0000; # # # # # # # entier virgule flottante notation scientifique soulign pour la lisibilit octal hexadcimal binaire

Comme Perl utilise la virgule comme sparateur de liste, elle ne peut servir comme sparateur des milliers pour les grands nombres. Pour amliorer leur lisibilit, Perl permet dutiliser la place le caractre soulign. Celui-ci ne fonctionne quavec des constantes numriques dfinies dans le programme, et non pour les chanes de caractres traites comme du numrique ou pour les donnes externes lues par ailleurs. De mme, les caractres initiaux 0x en hexadcimal et 0 en octal marchent uniquement avec les constantes. La conversion automatique dune chane en un nombre ne reconnat pas ces prfixes vous devez faire une conversion explicite11 avec la fonction oct (qui marche aussi pour les donnes hexadcimales condition dindiquer 0x ou 0b au dbut).

Chanes littrales
Les littraux alphanumriques sont habituellement dlimits par des apostrophes simples ou doubles. Ils fonctionnent un peu comme les quotes (les dlimiteurs de protection) sous UNIX : les apostrophes doubles permettent une interpolation des antislashs et des variables, les apostrophes simples non. (\ et \\ permettent dinclure un antislash dans une chane entre apostrophes simples). Si vous voulez inclure tout autre squence
10. Courant dans la culture UNIX, nest-ce pas. Si votre culture est diffrente, bienvenue dans la ntre ! 11. On simagine parfois que Perl devrait de lui-mme convertir toutes les donnes. Mais il existe beaucoup trop de nombres dcimaux avec des zros gauche dans le monde pour que Perl puisse le faire automatiquement. Par exemple, le code postal des bureaux de OReilly & Associates Cambridge, MA, est 02140. Le facteur aurait tendance snerver si votre programme dadressage de courrier transformait 02140 en la valeur dcimale 1120.

customer_8566

52

Chapitre 2 Composants de Perl

telle que \n (saut de ligne), vous devez utiliser les apostrophes doubles. (Les squences antislashs sont des squences dchappement car elles permettent d chapper temporairement linterprtation normale des caractres.) Une chane entre apostrophes simples doit tre spare du mot prcdent par un espace car ce caractre est valide mais archaque dans un identificateur. On utilise plutt la squence :: plus visuelle: $mainvar et $main::var reprsentent la mme variable, la deuxime tant beaucoup plus lisible. Les chanes entre guillemets permettent linterpolation de diffrents types de caractres bien connus dans les autres langages. Ils sont lists au tableau 2-1. Tableau 2-1. Caractres chapps avec antislash
Code \n \r \t \f \b \a \e \033 \x7f \cC \x{263a} \N{NAME} Signification Saut de ligne (gnralement LF). Retour chariot (gnralement CR). Tabulation horizontale. Saut de page. Retour arrire. Alerte (bip). Caractre ESC. ESC en octal. DEL en hexadcimal. Control-C. Unicode (smiley). Caractre nomm.

La notation \N{NOM} est utilise avec la directive use charnames dcrite au chapitre 31. Cette notation permet dutiliser les noms symboliques comme \N{GREEK SMALL LETTER SIGMA}, \N{greek:Sigma}, ou \N{sigma} suivant la directive utilise. Voir aussi le chapitre 15. Il existe de plus des squences dchappement pour modifier la casse des caractres qui suivent. Voir le tableau 2-2. Tableau 2-2. chappements de casse
Code \u \l \U \L \Q \E Signification Force le caractre suivant en majuscule ( titlecase en Unicode). Force le caractre suivant en minuscule. Force tous les caractres suivants en majuscules. Force tous les caractres suivants en minuscules. Prfixe avec antislash tous les caractres non alphanumriques. Fin de \U, \L, ou \Q.

customer_8566

Valeurs scalaires

53

Il est aussi possible dinsrer le caractre de saut de ligne dans une chane qui peut donc stendre sur plus dune ligne. Ceci peut tre utile, mais aussi dangereux si vous oubliez un guillemet, auquel cas lerreur sera annonce la prochaine occurrence de guillemet qui peut se trouver beaucoup plus loin dans votre fichier source. Heureusement ceci provoque immdiatement une erreur de syntaxe sur la mme ligne, et Perl est suffisamment fut pour vous avertir quil sagit peut-tre dune chane qui nest pas termine au bon endroit, et de plus il vous indique la ligne o la chane a d commencer. Paralllement aux squences dchappement ci-dessus, les chanes entre doubles apostrophes permettent une interpolation des variables scalaires et des listes de valeurs. Cela signifie que les valeurs de certaines variables peuvent tre directement insres dans une chane. Cest en fait une forme pratique de concatnation de chane.12 Linterpolation ne peut tre effectue que pour des variables scalaires, la totalit dun tableau (mais pas dun hachage), des lments unitaires dun tableau ou dun hachage, ou enfin, des tranches (des slections multiples dlments) de tableaux ou de hachages. En dautres termes, seules les expressions commenant par $ ou @ peuvent tre interpoles, car ce sont les deux caractres (avec lantislash) que lanalyseur de chane recherche. lintrieur dune chane, un caractre @ ne faisant pas partie de lidentifiant dun tableau ou dun hachage doit tre inclus dans une squence dchappement avec un antislash (@), sous peine dune erreur de compilation. Bien quun hachage complet spcifi par % ne puisse tre interpol dans une chane, un lment ou une slection multiples dlments dun hachage peuvent ltre car ils commencent respectivement par les caractres $ et @. Le bout de code suivant affiche "Le prix est de $100.".
$Prix = $100; print "Le prix est de $Prix.\n"; # non interpol # interpol

Comme dans certains shells, les accolades autour dun identifiant permettent de le diffrencier des autres caractres alphanumriques : "How ${verb}able!". En fait un identifiant entre accolades est forcment interprt en chane, comme les chanes clef dun hachage. Par exemple,
$jours{fev}

peut aussi tre crit :


$jours{fev}

et les apostrophes sont censes tre automatiquement prsentes. Mais toute chose plus complexe dans lindice sera interprte comme une expression. et vous devriez les mettre entre guillemets simples :
$jours{29 Fvrier} $jours{"29 Fvrier"} $jours{ 29 Fvrier } # Ok. # Ok. "" pas besoin dinterpoler. # mauvais, provoque un erreur de lecture.

En particulier, il est ncessaire dutiliser les simples guillemets dans les tranches de tableau :
12. Avec les warnings activs, Perl peut retourner une erreur sur des valeurs indfinies interpoles dans des chanes concatnes ou jointes, mme implicitement, le compilateur les crant pour vous.

customer_8566

54
@jours{Jan,Fev} @jours{"Jan","Fev"} @jours{ Jan, Fev }

Chapitre 2 Composants de Perl


# Ok. # Ok aussi. # erreur si la directive use strict est active

Excepts les indices de tableaux interpols ou de hachages, il nexiste pas de niveaux multiples dinterpolation. En particulier, contrairement aux attentes de nombreux programmeurs shell, les apostrophes inverses ne permettent pas dinterpoler lintrieur dapostrophes doubles. De mme, les apostrophes simples ne permettent pas dempcher lvaluation de variables lintrieur dapostrophes doubles. Linterpolation est trs puissante mais dun contrle strict en Perl. Elle ne se produit que dans les guillemets et certaines oprations que nous dcrirons dans la prochaine section.
print "\n"; print \n ; # Ok, imprime un saut de ligne. # MAUVAIS, pas de contexte dinterpolation.

Choisissez vos dlimiteurs


Alors que lon ne considre souvent les dlimiteurs que comme des constantes, ils fonctionnent plus comme des oprateurs avec Perl, permettant plusieurs formes dinterpolation et de correspondance de motifs. Perl fournit des dlimiteurs spcifiques pour ces fonctions, mais offre galement le moyen de choisir un dlimiteur pour chacune. Au tableau 2-3, on peut utiliser tout caractre autre qualphanumrique ou despace comme dlimiteur la place de /. (Les caractres saut de ligne et despace ne sont plus admis dans les nouvelles versions de Perl.) Tableau 2-3. Constructions avec guillemets
Habituelle "" `` () // s/// y/// "" Gnrique q// qq// qx// qw// m// s/// tr/// qr// Signification chane littrale chane littrale excution de commande liste de mots recherche de motif substitution de motif traduction expression rationnelle Interpolation non oui oui non oui oui non oui

Certains, ci-dessus, sont uniquement des formes de sucre syntaxique ; ils vitent dalourdir une chane avec trop dantislashs, en particulier dans les expressions rgulires o slash et antislash se ctoient. Si vous utilisez les guillemets simples comme dlimiteurs, aucune interpolation de variable ne sera faite (mme si le tableau ci-dessus indique oui ). Si le dlimiteur ouvrant est un crochet, une parenthse, une accolade ou le signe infrieur, le dlimiteur fermant doit lui correspondre (les occurrences de dlimiteurs doivent correspondre par paires). Par exemple :
$simple = q!Je dis "Tu dis, Elle la dit."!; $double = qq(On ne peut pas avoir une "bonne" $variable?);

customer_8566

Valeurs scalaires
$bout_de_code = q { if ($condition) { print "Pris!"; } };

55

Le dernier exemple montre quil est possible dutiliser le caractre espace entre loprateur de protection et le dlimiteur. Pour les constructions deux lments, comme s/// et tr///, si la premire paire de dlimiteurs est une accolade, la seconde partie peut en utiliser un autre : on peut crire s<foo>(bar) ou tr(a-f)[A-F]. Les espaces sont autoriss entre les deux paires de dlimiteurs, ainsi le dernier exemple peut scrire :
tr [a-z] [A-Z];

Les caractres espace sont toutefois interdits lorsque le dlimiteur est #. q#foo# est lu comme foo, alors que q #foo# est lu comme loprateur q suivi dun commentaire. Le dlimiteur sera pris sur la ligne suivante. Les commentaires peuvent tre placs au milieu dune construction deux lments, ce qui permet dcrire :
s {foo} {bar}; # Remplacer foo # par bar.

tr [a-f] # Translittration de minuscule hexa [A-F]; # vers majuscule hexa

Ou nen mettez pas du tout


Un mot qui na pas dinterprtation dans la grammaire sera trait comme sil tait dans une chane protge. Ce sont les mots simples.13 Comme pour les handles de fichier et les labels, un mot simple entirement en minuscules risque dentrer en conf lit avec un futur mot rserv. Si vous utilisez loption -w, Perl vous avertira de ce risque. Par exemple :
@jours = (Lun,Mar,Mer,Jeu,Ven); print STDOUT Salut, , monde, "\n";

stocke dans le tableau @jours les abrviations des jours de la semaine et affiche Salut tout le monde suivi dun saut de ligne sur STDOUT. En tant le handle de fichier, Perl essaiera dinterprter Salut comme un handle de fichier avec la clef une erreur de syntaxe. Cest tellement source derreur que certains voudront dclarer hors la loi les mots simples. Les oprateurs de protection lists ci-avant ont dautres formes y compris loprateur quote words qw// qui opre sur une liste de mots spars par des espaces :
@jours = qw(Lun Mar Mer Jeu Ven); print STDOUT "Salut, tout le monde\n";

Vous pouvez aussi bannir les mots simples de votre code. Si on crit :

13. Les noms de variables, descripteurs de fichier, labels et autres, ne sont pas considrs comme des mots simples car ils ont un sens qui dpend du mot prcdent ou suivant (ou les deux). Les noms prdfinis comme les noms de sous-programme nen sont pas non plus. Un mot simple le reste tant quil ny a pas la preuve du contraire.

customer_8566

56
use strict subs;

Chapitre 2 Composants de Perl

alors tout mot simple qui nest pas interprt comme un appel un sous-programme produit la place une erreur de compilation. Cette restriction dure jusqu la fin du bloc qui la contient. Un autre bloc peut lannuler par
no strict subs;

Il faut remarquer que les identifiants dans des constructions telles que :
"${verb}able" $jours{Fv}

ne sont pas considrs comme des mots simples car ils sont autoriss par une rgle explicite plutt que par le fait de ne pas avoir dinterprtation dans la grammaire . Un nom simple avec :: en fin, tel que main:: ou bien Chameau:: est toujours considr comme un nom de paquetage. Perl transforme Chameau:: en chane Chameau au moment de la compilation, et ne sera pas rejet par la directive use strict.

Interpolation des tableaux


Les variables tableau sont interpoles dans une chane entre doubles apostrophes en runissant tous leurs lments avec le dlimiteur spcifi dans la variable $"14 lespace sera pris par dfaut. Les exemples suivants sont quivalents :
$temp = join($",@ARGV); print $temp; print "@ARGV";

lintrieur des motifs de recherche (qui comprend aussi une interpolation identique celle des doubles guillemets) il existe une ambigut dplaisante : /$machin[chose]/ est-il interprt comme /${machin}[chose]} (o [chose] est une classe de caractres pour lexpression) ou comme /${machin[chose]}/ (o [chose] est lindice du tableau @machin) ? Si @machin nexiste pas, cest bien sr une classe de caractres. Si @machin existe, Perl devinera [chose], presque toujours bon escient.15 Sil dcrypte mal, ou si vous tes paranoaque, des accolades permettent de forcer linterprtation correcte comme cidessus. Et mme si vous tes simplement prudent, ce nest pas une mauvaise ide.

Documents ici-mme
Un format de sparation orient ligne est bas sur la syntaxe des documents icimme ( here documents) du shell16 Aprs les caractres <<, on saisit une chane destine terminer la partie dlimiter, toutes les lignes suivant la ligne courante jusqu
14. $LIST_SEPARATOR si vous utilisez le module English. 15. Le devin est trop ennuyeux dcrire compltement, mais, grosso modo, il fait une moyenne pondre de ce qui ressemble une classe de caractres (a-z, \w, les caractres initiaux ^) par rapport tout ce qui ressemble des expressions (les variables et les mots rservs). 16. Il est orient ligne dans le sens o les dlimiteurs sont les lignes plutt que des caractres. Le dlimiteur initial est la ligne courante, et celui de la fin est une ligne contenant la chane spcifie.

customer_8566

Valeurs scalaires

57

la chane de terminaison tant dlimites. La chane de terminaison peut tre un identifiant (un mot) comme du texte dlimit. Dans ce cas, le type de dlimiteur utilis dtermine le traitement du texte, comme en dlimitation standard. Un identifiant non dlimit fonctionne comme des apostrophes doubles. Il ne doit pas y avoir despace entre les caractres << et lidentifiant (un espace est trait comme un identifiant nul, ce qui est valable mais pas recommand, et correspond avec la premire ligne vide ; voir le premier exemple Hourra~! plus loin). La chane de terminaison doit apparatre en tant que telle (sans dlimiteurs et non entoure despaces) sur la dernire ligne.
print <<EOF; Le prix est $Prix. EOF print <<"EOF"; Le prix est $Prix. EOF print <<EOF; # avec des apostrophes simples Tout est possible (par exemple le passage dun chameau par le chas dune aiguille), cest vrai. Mais imaginez ltat du chameau, dform en un long fil sanglant de la tte aux pieds. -- C.S. Lewis EOF print << x 10; # affiche la ligne suivante 10 fois Les chameaux dbarquent! Ho u rra! Hourra! print <<"" x 10; # La mme chose, en mieux Les chameaux dbarquent! Ho u rra! Hourra! print <<`EOC`; # excute les commandes echo comment vas-tu echo yau de pole? EOC print <<"dromadaire", <<"camelide"; # on peut les empiler Je dis bactriane. dromadaire Elle dit lama. camelide # mme exemple que prcdemment

# mme exemple quau dessus avec des apostrophes # doubles explicites

Noubliez quand mme pas de mettre un point virgule la fin pour finir la phrase, car Perl ne sait pas que vous nallez pas essayer de faire ceci :
print <<ABC 179231 ABC + 20; # affiche 179251

Si vous voulez indenter vos documents ici-mme avec votre code, il faut enlever les espaces devant chaque ligne manuellement :

customer_8566

58
($quote = <<QUOTE) =~ s/^\s+//gm; The Road goes ever on and on, down from the door where it began. QUOTE

Chapitre 2 Composants de Perl

Il est aussi possible dinstancier un tableau avec les lignes dun document ici-mme comme suit :
@sauces = <<fin_lignes =~ m/(\S.*\S)/g; tomate normale tomate pice chili vert pesto vin blanc fin_lignes

Litral V-chane
Un litral qui commence avec un v suivi dun ou plusieurs entiers spars par des points est traduit en chane dont chaque atome a pour valeur ordinale chaque entier.
$crlf = v13.10; # valeur ASCII: retour chariot, saut de ligne

Le terme v-chane est une contraction de vecteur-chane ou version de chane . Il fournit une alternative plus cohrente pour construire une chane partir des valeurs numriques de chaque caractre. Par exemple, il est plus facile dcrire v1.20.300.4000 plutt que :
"\x{1}\x{14}\x{12c}\x{fa0}" pack("U*", 1, 20, 300, 4000) chr(1) . chr(20) . chr(300) . chr(4000)

Si un tel littral est compos de deux ou trois points (au moins trois entiers), le prfixe v peut tre omis.
print v9786; print v102.111.111; print 102.111.111; use 5.6.0; $ipaddr = 204.148.40.9; # affiche le caractre UTF-8 SMILEY, "\x{263a}" # affiche "foo" # idem # ncessite au moins cette version de Perl # laddresse IP de oreilly.com

Les v-chanes sont pratiques pour reprsenter les adresses IP ou les numros de version. En particulier avec le codage de caractres sur plus dun octet qui devient courant de nos jours, on peut comparer les numros de version de toute taille avec les v-chanes. Les numros de version et les adresses IP ne sont pas trs lisibles sous la forme de v-chanes. Pour obtenir une chane affichable utilisez loption v dans un masque avec printf, comme par exemple dans "%vd", tel que dcrit au chapitre 29. Pour en savoir plus sur les chanes Unicode, voir le chapitre 15, ainsi que la directive use bytes au chapitre 31 ; pour la comparaison des versions avec les oprateurs de comparaison de chane, voir $^V au chapitre 28 ; et pour la reprsentation des adresses IPv4, voir gethostbyaddr au chapitre 29.

customer_8566

Contexte

59

Autres symboles littraux


Tout symbole prfix par deux caractres soulign et postfix de mme est rserv pour un usage spcial par Perl. Deux mots spciaux, savoir __LINE__ et __FILE__, reprsentent le numro de la ligne courante et le fichier ce stade du programme. Ils ne peuvent tre utiliss que comme des mots spars ; ils ne sont pas interpols dans les chanes. De la mme manire, __PACKAGE__ est le nom du paquetage courant de compilation. Sil nexiste pas, ce qui est le cas lorsque la directive package; est vide, __PACKAGE__ vaut undef. Le symbole __END__, ou les caractres Control-D ou ControlZ, peuvent tre utiliss pour indiquer la fin logique du script courant avant la fin physique du fichier. Tout caractre suivant est ignor par le lecteur Perl mais peut tre lu via le descripteur spcial DATA. __DATA__ fonctionne de la mme faon que __END__, mais ouvre le handle de fichier DATA lintrieur de lespace de nom du paquetage courant, ce qui fait que si vous insrez plusieurs fichiers par require, chacun peut disposer de son handle DATA personnel et louvrir sans conf lit avec les autres. Pour en savoir plus, voir DATA au chapitre 28.

Contexte
Jusqu prsent, nous avons vu un certain nombre de termes pouvant produire des valeurs scalaires. Avant den voir davantage, nous devons aborder la notion de contexte.

Contexte scalaire et contexte de liste


Chaque opration17 dun script Perl est value dans un contexte spcifique, et la faon dont lopration se comportera peut dpendre des contraintes de ce contexte. Il existe deux contextes majeurs : les scalaires et les listes. Par exemple, laffectation dune variable scalaire value la partie droite dans un contexte scalaire :
$x = fonction(); # contexte scalaire $x[1] = fonction(); # contexte scalaire $x{"ray"} = fonction(); # contexte scalaire

Mais laffectation dun tableau ou dun hachage (ou dune tranche de ceux-ci) value la partie droite dans un contexte de liste. Laffectation dune liste de scalaire se fera aussi par un contexte de liste pour la partie droite.
@x = fonction(); # contexte de liste @x[1] = fonction(); # id @x{"ray"} = fonction(); # id %x = fonction(); # id

Laffectation une liste de scalaires fournit aussi un contexte de liste en rvalue, mme sil ny a quun seul lment dans la liste produite :
($x,$y,$z) = fonction(); # contexte de liste ($x) = fonction(); # id
17. Nous utilisons ce terme la fois pour oprateur et terme. Ces deux concepts se confondent lun et lautre lorsque lon commence parler de fonctions qui agissent comme des termes mais qui ressemblent des oprateurs unaires.

customer_8566

60

Chapitre 2 Composants de Perl

Ces rgles sont inchanges quand la variable est dclare avec les termes my ou our, ainsi nous avons :
my my my my $x @x %x ($x) = = = = fonction(); fonction(); fonction(); fonction(); # # # # contexte scalaire contexte de liste id id

Vous aurez beaucoup de problmes jusquau jour o vous aurez compris la diffrence entre le contexte scalaire et le contexte de liste, car certains oprateurs (tel notre fonction imaginaire fonction()), connaissent leur contexte de retour et typent leur valeur de retour en consquence. (Ce comportement sera toujours signal quand cest le cas.) En langage informatique, on dit que les oprateurs ont leur type de retour surcharg par le contexte daffectation. Il sagit de la surcharge la plus simple base sur deux types simples, le scalaire et la liste. Si certains oprateurs rpondent suivant le contexte, cest parce que quelque chose indique son type scalaire ou liste. Laffectation se comporte comme une fonction qui fournit son oprande de droite le contexte. On a besoin de savoir quel oprateur fournit quel contexte pour ses oprandes. Toutes les fonctions avec un contexte de liste, ont le terme LISTE dans leur description. Celles qui ne lont pas ont un scalaire. Cest en gnral assez intuitif.18 Au besoin, on peut forcer un contexte scalaire au milieu dun contexte de LISTE en utilisant la pseudo-fonction scalar. (Perl ne fournit pas le moyen de forcer un contexte de liste en contexte scalaire, car partout o un contexte de liste est prvu, ceci est dj indiqu par le contexte LISTE de certaines fonctions de contrle.) Le contexte scalaire peut ensuite tre class en contexte de chanes, numriques ou contexte tolrant. la diffrence de la distinction entre scalaire et liste que nous venons de faire, les oprations ne savent jamais quel type de contexte scalaire elles ont en entre. Elles se contentent de renvoyer le type de valeur scalaire quelles dsirent et laissent Perl traduire les numriques en chane dans un contexte de chane, et les chanes en nombres dans un contexte numrique. Certains contextes scalaires se moquent de savoir si une chane ou un numrique est retourn, ce qui fait quaucune conversion ne sera effectue. (Cela arrive, par exemple, lorsquon affecte une valeur une autre variable. Celle-ci prend simplement le mme sous-type que lancienne valeur.)

Contexte boolen
Le contexte boolen est un contexte scalaire particulier. Il correspond lendroit o une expression est value pour savoir si elle est vrai ou faux. Parfois nous crivons Vrai ou Faux la place de la dfinition technique utilise par Perl : une valeur scalaire est vrai si ce nest pas une chane nulle ou le nombre 0 (ou sa chane quivalente : "0"). Les rfrences sont toujours vraies. Une rfrence est toujours vraie car cest une adresse physique jamais nulle. Une valeur indfinie, appele undef, est toujours fausse car elle vaut, suivant le contexte, "" ou 0. (Les listes nont pas de valeur boolenne car elles ne sont jamais produites dans un contexte scalaire !)
18. Remarquez cependant que le contexte LISTE peut se propager aux appels de sous-programmes ultrieurs et il nest donc pas toujours facile de savoir dun seul coup dil si une phrase va tre value dans un contexte scalaire ou de liste. Le programme peut retrouver son contexte dans un sous-programme par la fonction wantarray.

customer_8566

Contexte

61

Puisque le contexte boolen est un contexte tolrant, il nentrane aucune conversion ; noter que cest un contexte scalaire, et tout oprande pour lequel cest ncessaire sera converti en scalaire. Et pour tout oprande le ncessitant, le scalaire retourn dans un contexte scalaire est une valeur boolenne possible, ce qui signifie par exemple quun oprateur retournant une liste, peut tre utilis dans un test boolen : la fonction unlink qui opre dans un contexte de liste, peut utiliser un argument de type array :
unlink @liste_fichiers; # dtruit chaque fichier de la liste.

Maintenant, utilisons le tableau dans une condition (donc contexte boolen), alors le tableau retourne sa cardinalit car il sait que cest un contexte scalaire ; cette valeur est vraie tant quil reste des lments dans le tableau. Supposons alors que nous voulons vrifier que les fichiers ont t supprims correctement, on crirait :
while (@liste_fichiers) { my $fichier = shift @liste_fichiers; unlink $fichier or warn "Ne peut pas supprimer $fichier: $!\n"; }

Ici @liste_fichier est value dans le contexte boolen induit par la boucle while, de telle sorte que Perl value le tableau pour voir si sa valeur est vraie ou fausse. Cette valeur est vraie tant que la liste contient des lments et devient fausse ds que le dernier lment est enlev (par loprateur shift). Notez que la liste nest pas value dans un contexte scalaire. Nous indiquons au tableau quil est scalaire et lui demandons ce quil vaut dans ce contexte. Nessayez pas dutiliser defined @files pour ce faire. La fonction defined regarde si le scalaire est gal undef, et un tableau nest pas un scalaire. Un simple test boolen suffit dans ce cas.

Contexte vide
Un autre type particulier des contextes scalaires est le contexte vide. Non seulement il se moque de la valeur retourner, mais en plus il ne veut mme pas de valeur de retour. Du point de vue du fonctionnement des fonctions, il nest pas diffrent des autres contextes scalaires, mais par le switch -w de la ligne de commande, le compilateur Perl prvient de lutilisation dune expression sans effet secondaire un endroit qui ne veut pas dune valeur, comme dans une phrase qui ne renvoie pas de valeur. Par exemple, si une chane est employe comme phrase :
"Camel Lot";

on peut obtenir un avertissement tel que :


Useless use of a constant in void context in monprog line 123;

Contexte interpolatif
Nous avons dj mentionn que les apostrophes doubles autour dune chane permettent une interpolation des variables et une interprtation des antislashs, mais le contexte interpolatif (souvent appel contexte double quotes ) ne sapplique pas quaux chanes entre doubles apostrophes. Les autres constructions double quotes concernent loprateur gnral apostrophe inverse qx//, loprateur de recherche de motif m// et

customer_8566

62

Chapitre 2 Composants de Perl

loprateur de substitution s/// et loprateur dexpression rgulire qr//. En fait, loprateur de substitution fait une interpolation de sa partie gauche avant de faire la recherche de motif, puis chaque motif trouv fait une interpolation de sa partie droite. Le contexte interpolatif nintervient quentre apostrophes, ou pour des choses qui fonctionnent de la mme faon, et il nest donc peut tre pas vraiment correct de lappeler contexte au mme titre que les contextes scalaires ou les contextes de liste (ou peut-tre bien que si).

Valeur de liste et tableaux


Maintenant que nous avons parl des contextes, nous pouvons parler des listes de valeurs et de leur comportement dans les diffrents contextes. Nous avons dj vu les listes de littraux, dfinies en sparant chaque valeur par une virgule (et en encadrant la liste par une paire de parenthses). Comme il nest pas gnant (presque jamais) dajouter des parenthses supplmentaires, la forme syntaxique dune liste scrit :
(LISTE)

Nous venons de voir que la forme LISTE indique un terme qui retourne une liste son argument, mais une liste littrale simple est lexception cette rgle en ce quelle fournit un contexte de liste uniquement quand la liste elle-mme est dans un contexte de liste. La valeur dune liste litrale dans un contexte de liste est simplement les valeurs de chaque lment spares par une virgule dans lordre spcifi. Comme un terme dans une expression, une liste litrale empile simplement des valeurs temporaires sur la pile Perl, elles seront utilises ensuite par loprateur qui attend cette liste. Dans un contexte scalaire, la valeur dune liste est la valeur de son dernier lment, comme avec loprateur virgule du C qui ignore toujours la valeur gauche et renvoie celle de droite (en faisant rfrence ce que nous disions plus haut, la partie gauche de la virgule fournit un contexte vide). Loprateur virgule tant associatif gauche, une liste de valeurs spares par des virgules fournit toujours le dernier lment car la virgule oublie chaque valeur prcdente. Par exemple :
@truc = ("un", "deux", "trois");

affecte toute la liste de valeurs au tableau @truc, mais :


$truc = ("un", "deux", "trois");

naffecte que la valeur trois la variable $truc. Comme pour le tableau @liste_fichiers, loprateur virgule sait sil est dans un contexte scalaire ou de liste et adapte son comportement en consquence. Cest important de souligner quune liste est diffrente dun tableau. Une variable tableau connat aussi son contexte, et dans un contexte de liste retourne la liste de ses valeurs internes comme une liste littrale. Mais dans un contexte scalaire elle retourne simplement sa longueur. Le code suivant affecte la valeur 3 la variable $truc :
@truc = ("un", "deux", "trois"); $truc = @truc;

Si vous pensiez obtenir la valeur trois , vous avez gnralis un peu vite car en fait Perl a dtect le contexte scalaire et na empil que la longueur du tableau. Aucun terme ou oprateur nempilera des valeurs de liste dans un contexte scalaire. Il empilera une

customer_8566

Valeur de liste et tableaux

63

valeur scalaire, qui ne sera certainement pas la dernire valeur de la liste quil retournerait dans un contexte de liste, valeur scalaire qui est ici la longueur du tableau. Il faut bien comprendre cet exemple (sinon, relisez le paragraphe car cest important). Retournons aux vraies LISTE, celles qui induisent un contexte de liste. Jusqu prsent nous avons soutenu que le contexte LISTE ne contient que des littraux. Mais en fait, toute expression qui retourne une valeur peut tre utilise lintrieur dune liste. Les valeurs ainsi utilises peuvent tre des valeurs scalaires ou des listes de valeurs. Le contexte LISTE fait automatiquement une interpolation des sous-listes. Cest pourquoi, lorsquun contexte LISTE est valu, chaque lment de la liste est valu dans ce contexte et la valeur de la liste rsultante est interpole dans LISTE comme si chaque lment individuel tait un membre de LISTE. Les tableaux perdent ainsi leur identit dans LISTE. La liste :
(@machin,@chose,&sousProgramme)

contient tous les lments de @machin, suivis de tous les lments de @chose, suivis de tous les lments renvoys par le sous-programme sousProgramme lorsquil est appel dans un contexte de liste. Notez que si lun quelconque des lments est nul, son interpolation ne compte pas. La liste nulle est reprsente par (). Son interpolation dans une liste na pas deffet. Ainsi ((),(),()) est quivalent (). De mme, linterpolation dun tableau sans lment donne, ce stade, la mme chose que sil navait pas t interpol. Une consquence est que lon peut mettre une virgule optionnelle la fin de toute liste. Ceci facilitera ultrieurement les ajouts dlments.
@nombres = ( 1, 2, 3, );

Le mot qw, que nous avons mentionn plus tt, permet aussi dentrer une liste littrale. Il construit quelque chose dquivalent une chane entre apostrophes clate sur plusieurs lignes. Par exemple :
@machin = qw( pomme orange mandarine poire ); banane goyave nectarine persimmon carambole kumquat pche prune

Remarquez que ces parenthses ne sont pas ordinaires et fonctionnent comme des apostrophes. On aurait pu aussi mettre des signes infrieur-suprieur, des accolades ou des slashs (mais les parenthses cest joli). Une liste de valeurs peut aussi tre indice comme un tableau standard. Vous devez alors mettre la liste entre parenthses (des vraies) pour viter toute ambigut. Si cela sert souvent pour obtenir une valeur du tableau, cest aussi une tranche de la liste et la forme syntaxique scrit :
(LISTE)[LISTE]

Exemples :
# Stat renvoie une valeur liste.

customer_8566

64
$modification_time = (stat($fichier))[8];

Chapitre 2 Composants de Perl

# ERREUR DE SYNTAXE ICI. $modification_time = stat($fichier)[8]; # OUPS, PAS DE PARENTHESES # Trouver un chiffre hexa. $chiffrehexa = (a,b,c,d,e,f)[$chiffre-10]; # Un "oprateur virgule inverse". return (pop(@machin),pop(@machin))[0]; # Affectation de plusieurs valeurs laide dune tranche. ($jour, $mois, $annee) = (localtime)[3,4,5];

Affectation de liste
Une liste est affecte si chacun de ses lments est affect :
($a, $b, $c) = (1, 2, 3); ($map{rouge}, $map{vert}, $map{bleu}) = (0xff0000, 0x00ff00, 0x0000ff);

Il est possible daffecter undef dans une liste. Cest utile pour ignorer certaines valeurs de retour dune fonction :
($dev, $ino, undef, undef, $uid, $gid) = stat($fichier);

Llment final dune liste peut tre un tableau ou un hachage :


($a, $b, @reste) = split; my ($a, $b, %reste) = @arg_list;

Vous pouvez mettre un tableau ou un hachage dans la liste affecte en sachant que le premier de ce type rencontr absorbera les valeurs restantes et les variables restantes seront initialises undef. Ceci peut tre utile dans une initialisation de type my ou local, o on veut que les tableaux soient vides. Il est aussi possible daffecter une liste vide :
() = fonction_bidon();

De cette faon, la fonction est appele dans un contexte de liste, mais on laisse tomber les valeurs renvoyes. Si vous aviez fait lappel sans affectation, la fonction aurait t value dans un contexte vide, qui est un contexte scalaire, et se serait comporte compltement diffremment. Laffectation de liste dans un contexte scalaire retourne le nombre dlments que fournit la partie droite de laffectation :
$x = ( ($machin,$truc) = (7,7,7) );# $x contient 3, pas 2 $x = ( ($machin,$truc) = f() ); # $x contient le nombre dlments de f() $x = ( () = f() ); # idem

Cest pratique lorsquon veut faire laffectation dune liste dans un contexte boolen, car la plupart des fonctions liste retourne une liste nulle lorsquelle se termine, valeur qui affecte un scalaire produit la valeur 0 qui vaut faux dans ce contexte. Voici un exem-

customer_8566

Hachages
ple dutilisation dans une boucle while :
while (($login, $password) = getpwent) { if (crypt($login, $password) eq $password) { print "$login a un mot de passe non scuris!\n"; } }

65

Longueur dun tableau


Le nombre dlments du tableau @jours est donn par lvaluation de @jours dans un contexte scalaire :
@jours + 0; scalar(@jours) # force implicitement @jours dans un contexte scalaire # force explicitement @jours dans un contexte scalaire

Attention, cela ne fonctionne que pour les tableaux. Cela ne fonctionne pas pour les listes de valeurs en gnral. Une liste avec des virgules comme sparateur value dans un contexte scalaire retournera la dernire valeur, comme loprateur virgule en C. Mais puisquil nest presque jamais ncessaire de connatre la longueur dune liste en Perl ce nest pas un problme. $#jours est trs proche de lvaluation scalaire de @jours. Cette dernire renvoie lindice du dernier lment du tableau, ou un de moins que la longueur puisquil existe (habituellement) un lment dindice zro. Laffectation de $#jours change la longueur du tableau. Raccourcir un tableau de la sorte dtruit les valeurs intermdiaires. Vous pouvez tre plus efficace en surdimensionnant lavance un tableau destin sagrandir (pour agrandir un tableau, on peut lui affecter un lment au-del de sa fin). Un tableau peut tre tronqu par laffectation de la liste nulle (). Les deux instructions suivantes sont quivalentes :
@nimportequoi = (); $#nimportequoi = -1;

Et celle qui suit est toujours vraie :


scalar(@nimportequoi) == $#nimportequoi + 1;

La troncation dun tableau ne rcupre pas la mmoire ainsi libre. Il faut faire un undef(@nimportequoi) pour rcuprer sa mmoire dans le processus courant. Vous ne pouvez vraisemblablement pas la retouner au systme dexploitation car peu de systmes en sont capables.

Hachages
Comme nous lavons dj dit, un hachage nest quun type spcial de tableau dans lequel on retrouve les valeurs par une chane-clef au lieu dun indice numrique. En fait, on dfinit des associations entre les clefs et les valeurs, et cest pourquoi les hachages sont souvent appels tableaux associatifs par les personnes assez courageuses pour taper sur un clavier. Il nexiste pas vraiment de syntaxe particulire aux hachages en Perl, mais si une liste ordinaire est affecte un hachage, chaque paire de valeur de la liste sera prise comme

customer_8566

66
une association clef/valeur.

Chapitre 2 Composants de Perl

%map = (rouge,0xff000,vert,0x00ff00,bleu,0x0000ff);

Ce qui a le mme effet que :


%map = (); $map{rouge} = 0xff0000; $map{vert} = 0x00ff00; $map{bleu} = 0x0000ff; # dabord initialiser le hachage

Il est souvent plus lisible dutiliser loprateur => entre la clef et sa valeur. Loprateur => est synonyme de la virgule, mais il est plus clair visuellement et permet aussi une sparation d identifiant gauche (comme les identifiants entre accolades ci-dessus) ; linitialisation des variables hachages devient plus simple :
%map = ( rouge => 0xff0000, vert => 0x00fff0, bleu => 0x0000ff, );

ou pour initialiser des rfrences banalises de hachage utilises comme des enregistrements :
$rec = { NOM => John Smith GRADE => Captain MATRICULE => 951413, };

ou pour utiliser des appels complexes de fonctions par un nom :


$field = $query->radio_group( NOM => group_name, VALEURS => [eenie,meenie,minie], DEFAUT => meenie, SAUTDELIGNE => true, LABELS => %labels, );

Mais nallons pas trop vite. Revenons nos hachages. Une variable hachage (%hachage) peut tre utilise dans un contexte de liste, toutes ses paires clef/valeurs tant interpoles dans la liste. Mais ce nest pas parce que le hachage a t initialis dans un certain ordre que les valeurs sont retournes dans le mme. Les hachages sont implments au niveau interne en utilisant des tables de hachage pour une recherche rapide, ce qui signifie que lordre dans lequel les donnes sont stockes dpend du type de fonction de hachage utilise pour dterminer la place de la paire clef/valeur. Ainsi, les entres sont apparemment retournes dans un ordre quelconque (au niveau dune paire clef/valeur, les deux lments sont bien sr rendus dans le bon ordre). Pour des exemples de rordonnancement en sortie, voir la fonction keys au chapitre 29. Si un hachage est valu dans un contexte scalaire, une valeur vraie est renvoye si et seulement si le hachage contient des paires clefs/valeurs. (Sil existe plusieurs paires, la valeur renvoye est une chane contenant le nombre de cellules utilises (buckets) et le nombre

customer_8566

Typeglobs et handles de fichiers

67

de cellules alloues, spars par un slash. Ceci nest utile que pour savoir si lalgorithme rsident de Perl traite correctement ou non lensemble de donnes. Par exemple, on entre 10 000 lments dans un hachage, mais lvaluation de %HASH dans un contexte scalaire rvle 1/8 , cela signifie que seulement une des 8 cellules a t touche, et quelle contient probablement les 10 000 lments. Ce nest pas cens se produire. Pour trouver le nombre de clefs dans un hachage, utilisez la fonction keys dans un contexte scalaire : scalar(keys(%HASH)). Il est possible dmuler un tableau multidimensionnel en spcifiant plus dune clef dans les accolades spares par une virgule. Les clefs listes sont concatnes ensemble spares par le caractre $; ($SUBSCRIPT_SEPARATOR) qui a la valeur chr(28) par dfaut. La clef rsultante devient une clef du hachage. Ces deux lignes font la mme chose :
$habitants{ $pays, $dpartement } = $rsultat_recensement; $habitants{ join $; =>; $pays, $dpartement } = $rsultat_recensement;

Cette fonctionalit fut lorigine implmente pour le traducteur a2p (awk vers perl). Aujourdhui, vous utiliseriez plus justement un tableau multidimensionnel comme il est dcrit au chapitre 9, Structures de donnes. Un usage encore pratique de cet ancien style est la liaison des hachages aux fichiers DBM (voir DB_File au chapitre 32, Modules standards), qui nimplmentent pas les clefs multidimensionnelles. Ne confondez pas lmulation multidimensionnelle des hachages avec les tranches de tableaux. Lun est une valeur scalaire, lautre reprsente une liste :
$hachage{ $x, $y, $z } @hachage{ $x, $y, $z } # une valeur simple # une tranche de trois valeurs

Typeglobs et handles de fichiers


Perl utilise un type spcial appel typeglob qui contient la table des types Perl pour ce symbole. (La table des symboles *foo contient les valeurs de $foo, @foo, %foo, &foo et dautres interprtations de foo.) Le prfixe de typage dun typeglob est * car il reprsente tous les types. Les typeglobs (ou leur rfrences) sont toujours utiliss pour passer ou stocker des handles de fichier. Pour sauvegarder un handle de fichier il faut taper :
$fh = *STDOUT;

ou comme une vraie rfrence, de cette manire :


$fh = \*STDOUT;

Cest aussi le moyen de crer un handle de fichier local. Par exemple :


sub newopen { my $path = shift; local *FH; # et non my ou our! open (FH, $path) || return undef; return *FH; # et non \*FH! } $fh = newopen(/etc/passwd);

Voir la fonction open pour gnrer dautres handles de fichiers.

customer_8566

68

Chapitre 2 Composants de Perl

Cependant, la principale utilisation des typeglobs est actuellement de servir dalias entre deux entres symboliques. Cest comme un surnom. Si on crit
*machin = $truc;

tout ce qui sappelle machin , est synonyme de tout ce qui sappelle truc . Lalias peut porter sur un seul type des variables du nom en affectant une rfrence :
*machin = $truc;

$machin devient alias de $truc, mais@machin nest pas synonyme de @truc, ni %machin de %truc. Tout ceci ne concerne que les variables globales, cest--dire dfinies dans un paquetage ; les variables lexicales ne peuvent tre accdes travers la table des symboles. Le mcanisme dimport/export est entirement bas sur ce principe, lalias ne prsuppose en effet aucune appartenance un module spcifique. Cette instruction :
local *Ici::bleu = \$Ailleurs::vert;

fait de $Ici::bleu un alias pour $Ailleurs::vert, mais ne fait pas de @Ici::bleu un alias pour @Ailleurs::vert, ni %Ici::bleu un alias pour %Ailleurs;::vert. Heureusement, toutes ces manipulations compliques de typeglobs sont transparentes la plupart du temps. Voir le chapitre 8, et Tables de symboles au chapitre 10 et le chapitre 11, Modules, pour un dveloppement sur ces sujets.

Oprateurs dentre
Nous allons maintenant prsenter plusieurs oprateurs dentre qui sont analyss comme des termes. En fait, on les appelle parfois des pseudo-littraux car ils agissent, dans bien des cas, comme des chanes protges (les oprateurs de sortie comme print fonctionnent comme des oprateurs de liste et sont traits au chapitre 29.)

Oprateur dexcution de commande (Backtick)


Premirement il y a loprateur de ligne de commande, aussi appell oprateur backtick, et qui ressemble ceci :
$info = `finger $user`;

Une chane protge par des apostrophes inverses procde tout dabord une interpolation des variables comme dans une chane entre apostrophes doubles. Le rsultat est alors interprt comme une commande par le shell, et la sortie de la commande devient la valeur de lidentifiant (ceci fonctionne comme certains oprateurs similaires des shells UNIX). Dans un contexte scalaire, le rsultat est une chane simple contenant toutes les sorties de la commande. Dans un contexte de liste, une liste de valeurs est renvoye, une pour chaque ligne sortie par la commande. (On peut utiliser $/ pour avoir un autre caractre de terminaison de ligne.) La commande est interprte chaque fois que lidentifiant est valu. La valeur numrique du statut de la commande est stocke dans $? (voir le chapitre 28 pour linterprtation de $?, connu aussi sous le nom de $CHILD_ERROR). la diffrence de csh, aucune transformation nest faite sur les donnes renvoyes ; les sauts de ligne restent des sauts de ligne. linverse de tous les shells, les apostrophes simples nempchent pas linterprtation des noms de variables. Pour passer un $ au shell il faut le cacher par un anti-

customer_8566

Oprateurs dentre

69

slash. Le $user de notre exemple ci-dessus est interpol par Perl, mais non par le shell (la commande lanant un processus shell, consultez le chapitre 23, Scurit, pour les problmes de scurit). La forme gnralise pour les apostrophes inverses est qx// (pour quoted execution, excution protge), mais loprateur fonctionne exactement de la mme faon que les apostrophes inverses ordinaires. Il suffit de choisir ses caractres de protection. Comme avec les pseudo-fonctions de protection, si vous choisissez un simple guillemet comme dlimiteur, la chane de commande nest pas interpole :
$perl_info = qx(ps $$); $shell_info = qxps $$; # Variable $$ de Perl # Variable $$ du shell

Oprateur de lecture de ligne (Angle)


Loprateur de lecture de ligne est loprateur le plus utilis, aussi connu sous le nom doprateur infrieur-suprieur, ou fonction readline. Lvaluation dun handle de fichier entre infrieur-suprieur (par exemple <STDIN>) donne la ligne suivante du fichier associ. Le saut de ligne est inclus, donc en accord avec les critres de vracit de Perl, chaque ligne lue a une valeur vrai, et lorsque le programme atteint la fin du fichier, loprateur angle retourne undef, cest--dire faux. On affecte dhabitude la valeur lue une variable, mais il existe un cas o une affectation automatique se produit. Si, et seulement si, loprateur de lecture de ligne est la seule chose prsente dans le test de boucle dun while, la valeur est automatiquement affecte la variable spciale $_. La valeur affecte est alors teste pour savoir si elle est dfinie (cela peut vous paratre idiot, mais vous utiliserez cette construction dans presque tous vos scripts Perl). Bref, les lignes suivantes sont toutes quivalentes :
while (defined($_ = <STDIN>)) { print $_; } # mthode longue while ($_ = <STDIN>) { print; } # utilise $_ explicitement while (<STDIN>) { print; } # mthode courte for (;<STDIN>;) { print; } # boucle while dguise print $_ while defined($_ = <STDIN>); # instruction modifie longue print while $_ = <STDIN>; # utilise $_ print while <STDIN>; # instruction modifie courte

Souvenez-vous que cette astuce requiert une boucle while. Si vous utilisez loprateur ailleurs, vous devez affecter le rsultat explicitement pour garder la valeur.
while (<FH1> && <FH2>) {...} if (<STDIN>) { print; } if ($_ = <STDIN>) { print; } if (defined($_ = <STDIN>)) { print; } # # # # # mauvais : perd les deux entres mauvais, affiche lancienne valeur de $_ ne teste pas si $_ est dfini meilleur

Quand la variable $_ est implicitement affecte dans une boucle, cest la variable globale dont il sagit. Vous pouvez protger la valeur de $_ de la manire suivante :
while (local $_ = <STDIN>) { print; } # utilise local $_

Lancienne valeur est rtablie la sortie de la boucle. $_ peut toujours tre accde depuis la boucle. Pour viter toute confusion, il est prfrable dutiliser une variable lexicale :
while (my $ligne = <STDIN>) { print $ligne; } # variable prive

customer_8566

70

Chapitre 2 Composants de Perl

(Ces deux boucles while testent si laffectation est defined, car my et local ne changent pas son comportement habituel.) Les handles de fichiers STDIN, STDOUT et STDERR sont prdfinis et ouverts. Dautres handles peuvent tre crs avec les fonctions open ou sysopen. Voir la documentation de ces fonctions au chapitre 29 pour les dtails. Dans la boucle while ci-dessus, la ligne dentre est value dans un contexte scalaire, chaque valeur est retourne sparment. Si on lutilise dans un contexte de liste, une liste de toutes les lignes dentre restantes est retourne, chaque ligne tant un lment de liste. Un important espace de donnes peut ainsi tre cr, et il faut donc lutiliser avec prcaution :
$une_ligne = <MYFILE>; # Donne la premire ligne. @toutes_lignes = <MYFILE>; # Donne le reste des lignes.

Il nexiste pas de magie particulire pour le while associ la forme liste de loprateur dentre, car la condition dune boucle while est toujours un contexte scalaire (comme toutes les conditions). Lutilisation du handle de fichier nul lintrieur de loprateur infrieur-suprieur (ou oprateur angle) est particulire et peut tre utilise pour muler la ligne de commande de programmes standards dUNIX tels que sed et awk. Quand on lit les lignes depuis <>, toutes les lignes de tous les fichiers mentionns sur la ligne de commande sont renvoyes. Si aucun fichier ntait spcifi, cest lentre standard qui est renvoye la place et le programme peut ainsi tre facilement insr entre des processus pour former un pipe. Voici comment cela fonctionne : la premire fois que <> est valu, le tableau @ARGV est contrl, et sil est nul, $ARGV[0] est mis - , qui donne lentre standard quand on louvre. Le tableau @ARGV est trait comme une liste de noms de fichiers. La boucle
while (<>) { ... } # code pour chacune des lignes

est quivalente au pseudo-code Perl suivant :


while (@ARGV and $ARGV[0] =~ /^-/) { $_=shift; last if /^--$/; if (/^-D(.*)/) { $debug = $1 } if (/^-V/) { $verbose++ } ... # autres alternatives } while (<>) { ... # du code dans chaque ligne }

part une meilleure lisibilit, le rsultat reste identique. Le tableau @ARGV est dcal et le nom du fichier courant est stock dans la variable $ARGV. Le handle de fichier ARGV est aussi utilis en interne ; <> est simplement un synonyme de <ARGV>, qui est magique (le pseudo-code ci-dessus ne fonctionne pas parce quil traite <ARGV> comme non-magique). Il est possible de modifier @ARGV avant linstruction <> du moment que le tableau est construit avec les noms de fichier que vous attendez. Le nom de fichier - qui reprsente lentre standard, peut tre ouvert avec la fonction open, ainsi que des f lux plus

customer_8566

Oprateurs dentre

71

sotriques comme gzip -dc < file.gz| ). Les numros de ligne ($.) sincrmentent comme sil nexiste quun fichier en entre. (Mais observez lexemple ci-dessous sur eof pour voir comment on rinitialise les numros de ligne chaque fichier.) Pour affecter @ARGV une liste de fichiers, cest direct :
# par dfaut: le fichier README si aucun argument nest donn @ARGV = ("README") unless @ARGV;

Pour passer des options dans un script, on peut utiliser un des modules Getopt ou mettre une boucle initiale telle que :
while ($_ = $ARGV[0], /^-/) { shift; last if /^--$/; if (/^-D(.*)/) { $debug = $1 } if (/^-v/) { $verbose++ } ... # autres options } while (<>) { ... # code pour chacune des lignes }

Le symbole <> ne renvoie faux quune seule fois. En cas dappel ultrieur, une autre liste @ARGV est suppose tre traite, et si @ARGV nest pas initialis les lectures se font depuis STDIN. Si la chane entre loprateur angle est une variable (par exemple, <$machin>), alors celle-ci contient le nom du fichier lire ou une rfrence celui-ci. Par exemple :
$fh = \*STDIN; $ligne = <$fh>;

ou :
open($fh, "<donnees.txt>"); $line = "<$fh>";

Oprateur de globalisation des noms de fichier


Vous vous souciez peut-tre de ce qui peut arriver un oprateur de lecture de ligne si vous mettez quelque chose de bizarre entre linfrieur et le suprieur. Il est alors transform en un oprateur diffrent. Si la chane lintrieur de loprateur angle est diffrente du nom dun handle de fichier ou dune variable scalaire (mme sil agit despace), elle sera interprte comme tant un motif de fichier globaliser .19 Le motif de recherche sapplique aux fichiers du rpertoire courant (ou dans le rpertoire spcifi dans le motif glob lui-mme), et les fichiers correspondants sont retourns par loprateur. Comme pour les lectures de ligne, les noms sont renvoys un un dans un contex19. Cela na rien voir avec les typeglobs dj cits, si ce nest quils utilisent tous deux le caractre * la faon dun joker. Le caractre * prend le surnom glob lorsquil est utilis de cette manire. Avec les typeglobs, on globalise les symboles homonymes dune table de symboles. Avec un glob de nom de fichier (global), on effectue une correspondance par des jokers des fichiers dun rpertoire, comme le font de nombreux shells.

customer_8566

72

Chapitre 2 Composants de Perl

te scalaire, ou tous la fois dans un contexte de liste. Ce dernier usage est en fait prdominant. Il est courant de voir :
my @fichiers = <*.xml>;

Comme pour dautre types de pseudo-constantes, un premier niveau dinterpolation est effectu, mais on ne peut pas crire <$machin> car il sagit dun handle de fichier indirect, comme nous lavons dj vu. Dans danciennes versions de Perl, les programmeurs insraient des accolades pour forcer une interprtation de nom de fichier glob : <${machin}>. De nos jours, on considre quil est plus propre dappeler la fonction interne directement par glob($machin), ce qui aurait d tre le cas ds lorigine. On crirait donc :
@fichiers = glob("*.xml");

si vous prfrez. Que lon utilise la fonction glob ou sa forme ancienne avec loprateur dangle, loprateur de globalisation fonctionne de la mme faon dans une boucle que loprateur while en affectant le rsultat $_. (Ce fut la premire raison de surcharger cet oprateur.) Par exemple, si vous vouliez changer les autorisations de fichiers de code C, vous cririez :
while (glob "*.c") { chmod 0644, $_; }

ce qui est quivalent :


while (<*.c>) { chmod 0644, $_; }

La fonction glob tait implmente comme une commande shell dans les anciennes versions de Perl (aussi dans les anciennes versions dUnix), tait plus coteuse en ressources et ne fonctionnait pas de la mme faon sur tous les systmes. Cest aujourdhui une fonction prdfinie plus fiable et plus rapide. Voyez la description du module File::Glob au chapitre 32 pour modifier son comportement par dfaut pour, par exemple, traiter les espaces dans ces arguments, lexpansion de certains caractres (tilde ou accolade), linsensiblit la casse ou bien le classement des valeurs retournes, entre autres choses. Bien sr, la faon la plus courte et la moins lisible pour faire la commande chmod ci-dessus, est dutiliser la globalisation comme un oprateur sur liste :
chmod 0644, <*.c>;

Un glob nvalue son argument que quand il dmarre une nouvelle liste. Toutes les valeurs doivent tre lues avant son excution. Dans un contexte de liste, ce nest pas trs important, puisquon les a toutes automatiquement. Mais dans un contexte scalaire, loprateur renvoie la prochaine valeur chaque appel, ou une valeur fausse si on arrive au bout. Attention, faux nest retourn quune seule fois. Ainsi, si lon attend une valeur unique pour un glob, il vaut mieux crire :
($fichier) = <blurch*>; # contexte de liste # contexte scalaire

au lieu de :
$fichier = <blurch*>;

customer_8566

Oprateurs dentre

73

car la premire forme avale tous les noms de fichier correspondants et rinitialise loprateur, alors que ce que renvoie la seconde alterne entre un nom de fichier et faux. Pour interpoler des variables, il faut absolument utiliser loprateur glob, car lancienne syntaxe peut tre confondue avec la notation indirecte des handles de fichiers. Mais ce niveau, il devient vident que la frontire entre les termes et les oprateurs est un peu f loue.
@files = <$dir/*.[ch]>; @files = glob("$dir/*.[ch]"); @files = glob $un_motif; # viter # appelle glob en tant que fonction # appelle glob en tant quoprateur

Nous ne mettons pas les parenthses dans le second exemple pour montrer que glob peut tre utilis comme un oprateur unaire, cest--dire un oprateur prfixe avec un seul argument. Loprateur glob est un exemple doprateur unaire dfini, qui nest quun des types doprateurs dont nous parlerons dans le prochain chapitre. Ensuite nous parlerons des oprations de recherche de motif, qui ressemblent elles aussi des termes, mais fonctionnent comme des oprateurs.

customer_8566

customer_8566

Oprateurs unaires et binaires


Dans le chapitre prcdent, nous avons parl des diffrents types de termes que vous pouvez utiliser dans une expression. Mais pour tre honnte, les termes isols sont un peu ennuyeux. Beaucoup de termes sont de joyeux ftards ; ils aiment comuniquer les uns avec les autres. Un terme typique ressent une forte envie de sidentifier avec dautres termes, ou de les inf luencer de diffrentes manires. Cependant, il existe de nombreuses sortes dinteractions sociales et de nombreux niveaux dimplication. En Perl, ces relations sont exprimes laide doprateurs. Il faut bien que la sociologie serve quelque chose. Dun point de vue mathmatique, les oprateurs sont des fonctions ordinaires avec une syntaxe spciale. Dun point de vue linguistique, les oprateurs sont juste des verbes du troisime groupe. Mais comme tout linguiste vous le dira, les verbes du troisime groupe sont gnralement ceux que lon utilise le plus souvent. Cest important du point de vue de la thorie de linformation, car les verbes du troisime groupe sont gnralement plus courts et plus efficaces tant pour la production que pour la reconnaissance. Dun point de vue pratique, les oprateurs sont maniables. On distingue plusieurs varits doprateurs, en fonction de leur arit (le nombre doprandes quils prennent), leur prcdence (leur capacit prendre leurs oprandes aux oprateurs voisins), et leur associativit (agissent-ils de gauche droite ou de droite gauche quand ils sont associs des oprateurs de mme prcdence). Les oprateurs Perl se prsentent sous trois arits : unaire, binaire ou ternaire. Les oprateurs unaires sont toujours des oprateurs prfixes (excepts les oprateurs de post-incrmentation et de post-dcrmentation).1 Tous les autres sont des oprateurs infixes moins que vous ne comptiez les oprateurs de liste, qui peuvent prcder autant darguments que vous voulez. Cependant la plupart des gens prfrent voir les oprateurs de liste comme des fonctions normales autour desquelles on peut oublier de mettre des parenthses. Voici quelques exemples :
1. Bien que lon puisse galement voir les diffrents types de guillemets et de parenthses (crochets, accolades) comme des oprateurs circonfixes qui englobent et dlimitent des termes.

customer_8566

76
! $x $x * $y $x ? $y : $z print $x, $y, $z # # # # un un un un oprateur oprateur oprateur oprateur

Chapitre 3 Oprateurs unaires et binaires


unaire binaire ternaire de liste

La prcdence dun oprateur dtermine sa force dattraction. Les oprateurs de plus haute prcdence capturent les arguments qui les entourent avant les oprateurs de moindre prcdence. Lexemple typique sort tout droit des mathmatiques lmentaires, o la multiplication est prioritaire sur laddition :
2 + 3 * 4 # vaut 14, et non 20

Lordre dans lequel sont excuts deux oprateurs de mme prcdence dpend de leur associativit. Les rgles suivent en partie les conventions des mathmatiques :
2 * 3 * 4 2 ** 3 ** 4 2 != 3 != 4 # signifie (2 * 3) * 4, associatif gauche # signifie 2 ** (3 ** 4), associatif droite # illgal, car non associatif

Le tableau 3-1 liste lassociativit et larit des oprateurs Perl par ordre de prcdence dcroissante. Tableau 3-1. Prcdence des oprateurs
Associativit Non associatifs Gauche Non associatifs Droite Droite Gauche Gauche Gauche Gauche Droite Non associatifs Non associatifs Gauche Gauche Gauche Gauche Non associatifs Droite Droite Gauche Droite Droite Arit 0 2 1 2 1 2 2 2 2 0,1 2 2 2 2 2 2 2 3 2 2 0+ 1 Classe de prcdence Termes et oprateurs de liste (vers la gauche) -> ++ -** ! ~ \+ unaire et - unaire =~ !~ * / % x + - . << >> Oprateurs unaires nomms < > <= >= lt gt le ge == != <=> eq ne cmp & | ^ && || ..... ?: = += -= *= et suivants , => Oprateurs de liste (vers la droite) not

customer_8566

Termes et oprateurs de listes (vers la gauche)


Tableau 3-1. Prcdence des oprateurs (suite)
Associativit Gauche Gauche Arit 2 2 Classe de prcdence and or xor

77

Vous pourriez penser quil y a bien trop de niveaux de prcdence se souvenir. Et bien vous avez raison. Heureusement, deux choses jouent en votre faveur. Dabord les niveaux de prcdence tels quils sont dfinis sont en gnral assez intuitifs, en supposant que vous ntes pas psychotique. Ensuite, si vous tes seulement nvros, vous pouvez toujours ajouter des parenthses supplmentaires pour calmer votre angoisse. Notez galement que tous les oprateurs emprunts C conservent les mmes relations de prcdence entre eux, mme quand les rgles de prcdence de C sont lgrement biscornues. (Cela rend Perl dautant plus facile apprendre pour les personnes qui connaissent C ou C++. Peut-tre mme pour celles qui connaissent Java.) Les sections qui suivent couvrent ces oprateurs dans leur ordre de prcdence. de trs rares exceptions, ils oprent tous uniquement sur des valeurs scalaires et non sur des listes. Nous indiquerons les exceptions quand elles se prsenteront. Bien que les rfrences soient des valeurs scalaires, utiliser la plupart de ces oprateurs sur des rfrences na pas beaucoup de sens, car la valeur numrique dune rfrence na de signification que dans les profondeurs de Perl. Nanmoins, si une rfrence pointe sur un objet dune classe qui autorise la surcharge doprateurs, vous pouvez utiliser ces oprateurs sur cet objet ; si la classe a dfini une surcharge pour tel ou tel oprateur, cela dcrit comment lobjet sera trait par cet oprateur. Cest ainsi par exemple que les nombres complexes sont implments en Perl. Pour plus dinformations sur la surcharge doprateurs, voir le chapitre 13, Surcharge.

Termes et oprateurs de listes (vers la gauche)


En Perl, tout terme est de prcdence maximale. Les termes comprennent les variables, les apostrophes et les oprateurs de type quote, la plupart des expressions entre parenthses, crochets ou accolades, et toute fonction dont les arguments sont entre parenthses. En fait, si on regarde les choses ainsi, il ny a pas vraiment de fonctions, mais seulement des oprateurs de liste et des oprateurs unaires qui se comportent comme des fonctions parce que vous avez mis des parenthses autour de leurs arguments. Tout cela nempche pas le chapitre 29 de sappeler Fonctions. Maintenant lisez attentivement. Voici quelques rgles trs importantes qui simplifient grandement les choses, mais qui peuvent loccasion produire des rsultats contraires lintuition pour les imprudents. Si un oprateur de liste (comme print) ou un oprateur unaire nomm (comme chdir) est suivi dune parenthse ouvrante comme token suivant (sans tenir compte des blancs), loprateur et ses arguments entre parenthses ont la prcdence la plus haute, comme sil sagissait dun appel de fonction normal. La rgle est la suivante : si cela ressemble un appel de fonction, alors cest un appel de fonction. Vous pouvez le faire ressembler une non-fonction en prfixant les parenthses avec un plus unaire, qui ne fait absolument rien smantiquement parlant ; il ne convertit mme pas les arguments en numrique.

customer_8566

78

Chapitre 3 Oprateurs unaires et binaires

Par exemple, puisque || a une prcdence plus faible que chdir, nous aurons :
chdir $toto chdir($toto) chdir ($toto) chdir +($toto) || || || || die; die; die; die; # # # # # # # # (chdir (chdir (chdir (chdir $toto) $toto) $toto) $toto) || || || || die die die die

mais comme * a une prcdence plus grande que chdir, nous aurons :
chdir $toto * 20; chdir($toto) * 20; chdir ($toto) * 20; chdir +($toto) * 20; chdir ($toto * 20) (chdir $toto) * 20 (chdir $toto) * 20 chdir ($toto * 20)

De mme pour nimporte quel oprateur numrique qui est galement un oprateur unaire nomm, comme rand :
rand 10 * 20; rand(10) * 20; rand (10) * 20; rand +(10) * 20; # # # # rand (10 * 20) (rand 10) * 20 (rand 10) * 20 rand (10 * 20)

En labsence de parenthses, la prcdence doprateurs de liste comme print, sort, ou chmod est soit trs haute soit trs basse selon que vous regardez gauche ou droite de loprateur (cest le sens du vers la gauche dans le titre de cette section). Par exemple, dans :
@tab = (1, 3, sort 4, 2); print @tab; # imprime 1324

Les virgules droite de sort sont values avant le sort, mais les virgules sa gauche sont values aprs. En dautres termes, un oprateur de liste tend avaler tous les arguments qui le suivent, puis se comporter comme un simple terme pour lexpression qui le prcde. Il vous faut encore tre prudent avec les parenthses :
# Ces arguments sont valus avant de faire le print : print($toto, exit); # videmment pas ce que vous voulez. print $toto, exit; # Ici non plus. # Ces lignes font le (print $toto), exit; print($toto), exit; print ($toto), exit; print avant dvaluer lexit : # Cest ce que vous voulez. # Ici aussi. # Et mme ceci.

Le cas le plus simple pour se faire piger, cest quand vous utilisez des parenthses pour grouper des arguments mathmatiques, en oubliant que les parenthses servent aussi regrouper les arguments de fonctions :
print ($toto & 255) + 1, "\n"; # affiche ($toto & 255)

Cela ne fait probablement pas ce quoi vous vous attendiez au premier coup dil. Heureusement, les erreurs de cette nature provoquent des avertissements comme Useless use of addition in a void context quand les avertissements sont activs (avec loption de ligne de commande -w). Les constructions do {} et eval {} sont aussi analyses comme des termes, de mme que les appels de sous-programmes et de mthodes, les crateurs de tableaux et de hachages anonymes, [] et {}, et le crateur de sous-programme anonymes sub {}.

customer_8566

Loprateur flche

79

Loprateur f lche
Tout comme en C et en C++, loprateur binaire ->est un oprateur infixe de drfrencement. Si droite on trouve un indice de tableau entre [...], un indice de hachage entre {...} ou une liste darguments de sous-programme entre (...), alors la partie gauche de la f lche doit tre respectivement une rfrence (symbolique ou en dur) de tableau, de hachage ou de sous-programme. Dans un contexte de lvalue (o lon peut affecter une valeur), si la partie gauche nest pas une rfrence, elle doit tre capable de contenir une rfrence, auquel cas cette rfrence sera autovivifie pour vous. Pour en savoir plus ce sujet (et pour quelques avertissements sur lautovivification accidentelle), voir le chapitre 8, Rfrences.
$aref->[42] $href->{"corned beef"} $sref->(1,2,3) # un drfrencement de tableau # un drfrencement de hachage # un drfrencement de sous-programme

Sinon, cest une sorte dappel de mthode. La partie droite doit tre un nom de mthode (ou une simple variable scalaire contenant le nom de la mthode) et la partie gauche doit svaluer soit comme un objet (une rfrence consacre), soit comme un nom de classe (cest--dire un nom de paquetage) :
$yogi = Ours->new("Yogi"); $yogi->pique($piquenique); # un appel de mthode de classe # un appel de mthode sur une instance

Le nom de mthode peut tre qualifie avec un nom de paquetage pour indiquer dans quelle classe commencer chercher la mthode, ou avec le nom de paquetage spcial SUPER::, pour indiquer que la recherche doit commencer dans la classe parente. Voir le chapitre 12, Objets.

Auto-incrmentation et autodcrmentation
Les oprateurs ++ et -- fonctionnent comme en C. Cest--dire que, placs avant une variable, ils lincrmentent ou la dcrmentent avant den renvoyer la valeur. Quand ils sont placs aprs, ils lincrmentent ou la dcrmentent aprs en avoir renvoy la valeur. Par exemple, $A++2 incrmente la valeur de la variable $A et en retourne la valeur avant de raliser lincrmentation. De mme, --$b{(/(\w+)/)[0]} dcrmente llment du hachage %b index par le premier mot de la variable de recherche par dfaut ($_) et renvoie la valeur aprs la dcrmentation.3
2. N.d.T. : Pour dintressantes variations sur $A++, vous pouvez consulter http://paris.mongueurs.net/aplusplus.html. 3. Bon daccord, ce ntait pas trs sympa. Nous voulions juste tre srs que vous suiviez. Voici comment cette expression fonctionne. Dabord, la recherche de motif trouve le premier mot de $_ en utilisant lexpression rgulire \w+. Les parenthses qui lentourent permettent de retourner le mot comme valeur dans une liste un seul lment car la dtection se fait dans un contexte de liste. Le contexte de liste est fourni par loprateur de tranche de liste, (...)[0], qui retourne le premier (et unique) lment de la liste. Cette valeur est utilise comme cl pour le hachage et lentre du hachage (sa valeur) est dcrmente et retourne. En gnral, quand vous tes confront une expression complexe, analysez-la de lintrieur vers lextrieur pour voir dans quel ordre les vnements se produisent.

customer_8566

80

Chapitre 3 Oprateurs unaires et binaires

Loprateur dauto-incrmentation comporte en plus un peu de magie. Si vous incrmentez une variable qui est numrique, ou qui a t utilise un moment donn dans un contexte numrique, vous avez une incrmentation normale. Si au contraire la variable na t utilise que dans des contextes de chane depuis quelle a t affecte, que sa valeur est non nulle et correspond au motif /^[a-zA-Z]*[0-9]*$/, lincrmentation est faite sur la chane, en prservant chaque caractre dans son domaine, avec une retenue :
print print print print ++($toto ++($toto ++($toto ++($toto = = = = 99); a9); Az); zz); # # # # prints prints prints prints 100 b0 Ba aaa

lheure o nous crivons ces lignes, lauto-incrmentation magique na pas t tendue aux lettres et chiffres Unicode, mais pourrait ltre dans le futur. Loprateur dautodcrmentation nest, lui, pas magique, et il nest pas prvu que cela change.

Exponentiation
Loprateur ** binaire est loprateur dexponentiation. Notez quil lie encore plus fortement que le moins unaire ; cest pourquoi -2**4 vaut -(2**4), et non (-2)**4. Loprateur est implment grce la fonction pow(3) de C, qui fonctionne en interne avec des nombres en virgule f lottante. Les calculs sont faits grce des logarithmes, ce qui signifie quil fonctionne avec des puissances fractionnaires, mais que vous obtiendrez parfois des rsultats moins prcis quavec une simple multiplication.

Oprateurs unaires idographiques


La plupart des oprateurs portent simplement des noms (voir Oprateurs unaires nomms et de test de fichier plus loin dans ce chapitre), mais certains oprateurs sont jugs suffisament importants pour mriter leur propre reprsentation symbolique spciale. Ces oprateurs semblent tous avoir un rapport avec la ngation. Plaignez-vous auprs des mathmaticiens. Le ! unaire ralise une ngation logique, cest--dire un non . Voyez not pour une version de moindre prcdence du non logique. La valeur dun oprande ni est vraie (1) si loprande est faux (0 numrique, chane "0", chane vide ou valeur indfinie) et fausse ("") si loprande est vrai. Le - unaire effectue une ngation arithmtique si son oprande est numrique. Si loprande est un identificateur, une chane compose dun signe moins concatn lidentificateur est renvoye. Sinon, si la chane commence avec un plus ou un moins, une chane commenant avec le signe oppos est renvoye. Un des effets de ces rgles est que -motsimple est quivalent "-motsimple". Cest particulirement utile aux programmeurs Tk. Le ~ unaire ralise une ngation sur les bits, cest--dire un complment 1. Par dfinition, ce nest pas vraiment portable quand cest limit par la taille du mot-machine de votre ordinateur. Par exemple, sur une machine 32 bits ~123 vaut 4294967172, tandis

customer_8566

Oprateurs de liaison

81

que sur une machine 64 bits, cela vaut 18446744073709551492. Mais vous le saviez dj. Ce que vous ne saviez peut-tre pas, cest que si largument de ~ est une chane au lieu dun nombre, une chane de mme longueur est renvoye avec tous ses bits complments. Cest une manire rapide de basculer un grand nombre de bits dun coup, et de faon portable puisque cela ne dpend pas de la taille de votre mot-machine. Plus tard nous verrons aussi les oprateurs logiques sur les bits, qui ont eux des variantes pour les chanes. Le + na aucun effet smantique, mme sur les chanes. Son utilit est surtout syntaxique, pour sparer le nom dune fonction dune expression entre parenthses qui serait sinon interprte comme la liste complte des arguments de la fonction. (Voir les exemples dans la section Termes et oprateurs de listes (vers la gauche).) Si vous y rf lchissez dune manire un peu dtourne, le + inverse leffet quont les parenthses de changer les oprateurs prfixes en fonctions. Le \ cre une rfrence sur ce qui le suit. Utilis sur une liste, il cre une liste de rfrences. Voir la section Loprateur antislash au chapitre 8 pour plus de dtails. Attention ne pas confondre ce comportement avec celui de lantislash dans une chane, bien que les deux formes comportent la notion vaguement ngative de protection de leurs arguments contre linterprtation. Cette ressemblance nest pas purement fortuite.

Oprateurs de liaison
Le =~ binaire lie une expression scalaire un oprateur de recherche de motif, de substitution ou de translittration (ngligemment appele traduction). Ces oprations chercheraient ou modifieraient sinon la chane contenue dans $_(la variable par dfaut). La chane lier est place gauche, tandis que loprateur lui-mme est plac droite. La valeur de retour indique le succs ou lchec de lopration effectue droite, puisque loprateur de lien ne fait rien par lui-mme. Si largument de droite est une expression plutt quune recherche de motif, une substitution ou une translittration, il sera interprt comme une recherche de motif lexcution. Cest--dire que $_ =~ $pat est quivalent $_ =~ /$pat/. Cest moins efficace quune recherche explicite, puisque le motif doit tre vrifi et potentiellement recompil chaque fois que lexpression est value. Vous pouvez viter cette recompilation en prcompilant le motif original avec loprateur qr// de citation dexpression rgulire ( quote regex en anglais). Le !~ binaire est identique =~sauf que la valeur de retour est inverse logiquement. Les expressions suivantes sont fonctionnellement quivalentes :
$chaine !~ /pattern/ not $chaine =~ /pattern/

Nous avons dit que la valeur de retour indique le succs, mais il existe plusieurs sortes de succs. La substitution renvoie le nombre de substitutions russies, comme la translittration. (En fait, la translittration sert souvent compter les caractres.) Puisque nimporte quel rsultat non nul est vrai, tout fonctionne. La forme de valeur vraie la plus spectaculaire est une valeur de liste : en contexte de liste, les recherches de motif peuvent renvoyer les sous-chanes captures par les parenthses dans le motif. Conformment aux rgles de laffectation de liste, cette affectation retournera vrai si quelque

customer_8566

82

Chapitre 3 Oprateurs unaires et binaires

chose a t dtect et affect, et faux dans le cas contraire. Cest pourquoi vous voyez parfois des choses comme :
if ( ($c,$v) = $chaine =~ m/(\w+)=(\w*)/ ) { print "CLE $c VALEUR $v\n"; }

Dcomposons tout cela. Le =~ a la prcdence sur =, il se produit donc en premier. Le =~lie $chaine la recherche de motif droite. Celle-ci recherche ce qui ressemble CLE=VALEUR dans votre chane. Il se trouve en contexte de liste, car du ct droit dune affectation de liste. Si le motif est trouv, il renvoie une liste affecter $c et $v. Laffectation de liste elle-mme se trouve dans un contexte scalaire et renvoie donc 2, le nombre de valeurs droite de laffectation. Et il se trouve que 2 est vrai, puisque notre contexte scalaire est aussi un contexte boolen. Quand la recherche choue, aucune valeur nest affecte, ce qui renvoie 0, qui est faux. Voir le chapitre 5, Recherche de motif, pour en savoir plus sur le fonctionnement des motifs.

Oprateurs multiplicatifs
Perl fournit des oprateurs proches de ceux de C : * (multiplication), / (division) et % (modulo). * et / fonctionnent exactement comme vous vous y attendez, en multipliant ou divisant leurs deux oprandes. La division se fait en virgule f lottante, moins que vous nayez spcifi le pragma integer. Loprateur % convertit ses oprandes en entiers avant de calculer le reste de la division entire. (Nanmoins cette division est faite en virgule f lottante donc vos oprandes peuvent faire 15 chiffres sur la plupart des machines 32 bits.) Supposons que nos deux oprandes sappellent $a et $b. Si $b est positif, alors le rsultat de $a % $b est $a moins le plus grand multiple de $b infrieur $a (ce qui veut dire que le rsultat sera toujours dans lintervalle 0 .. $b-1). Si $b est ngatif, alors le rsultat de $a % $b est $a moins le plus petit multiple de $b suprieur $a (ce qui veut dire que le rsultat sera toujours dans lintervalle $b+1 .. 0). Quand on est porte de use integer, % vous donne directement accs loprateur modulo tel quil est implment par votre compilateur C. Cet oprateur nest pas bien dfini pour les oprandes ngatifs, mais sexcutera plus rapidement. Le x est loprateur de rptition. En ralit, il sagit de deux oprateurs. En contexte scalaire, il retourne une chane concatne compose de loprande de gauche rpt le nombre de fois spcifi par loprande de droite. (Pour assurer la compatibilit avec les versions prcdentes, il le fait galement en contexte de liste si largument de gauche nest pas entre parenthses.)
print - x 80; print "\t" x ($tab/8), x ($tab%8); # imprime une range de tirets # tabule la colonne $tab

En contexte de liste, si loprande de gauche est une liste entre parenthses, x fonctionne comme un rplicateur de liste plutt que comme un rplicateur de chane. Cela peut servir initialiser la mme valeur tous les lments dun tableau de longueur indtermine.
@ones = (1) x 80; @ones = (5) x @ones; # une liste de 80 1 # met tous les lments 5

customer_8566

Oprateurs additifs

83

De la mme manire, vous vous pouvez galement utiliser x pour initialiser des tranches de tableaux et de hachages.
@cles = qw(du Perl aux cochons); @hash{@cles} = ("") x @cles;

Si cela vous laisse perplexe, remarquez que @cles est utilis la fois comme une liste gauche de laffectation et comme une valeur scalaire (qui renvoie la longueur du tableau) droite. Lexemple prcdent a le mme effet sur %hash que :
$hash{du} $hash{Perl} $hash{aux} $hash{cochons} = = = = ""; ""; ""; "";

Oprateurs additifs
tonnament, Perl dispose des oprateurs usuels + (addition) et - (soustraction). Ces deux oprateurs convertissent leurs arguments de chane en valeurs numriques si ncessaire, et renvoient un rsultat numrique. Perl fournit galement loprateur . qui ralise la concatnation de chanes. Par exemple :
$presque = "Fred" . "Pierrafeu"; # renvoie FredPierrafeu

Remarquez que Perl najoute pas despace entre les chanes concatnes. Si vous voulez lespace ou si vous avez plus de deux chanes concatner, vous pouvez utiliser loprateur join, dcrit au chapitre 29, Fonctions. Cependant, la plupart du temps on concatne implicitement dans une chane entre doubles apostrophes :
$nomcomplet = "$prenom $nom";

Oprateurs de dcalage
Les oprateurs de dcalage de bits (<< et >>) renvoient la valeur de largument de gauche dcal gauche (<<) ou droite (>>) du nombre de bits spcifi par largument de droite. Les arguments doivent tre des entiers. Par exemple :
1 << 4; 32 >> 4; # renvoie 16 # renvoie 2

Faites attention cependant, car les rsultats sur de grands nombres (ou sur des nombres ngatifs) peuvent dpendre du nombre de bits utiliss par votre machine pour reprsenter les entiers.

Oprateurs unaires nomms et de test de fichier


Certaines des fonctions dcrites au chapitre 29 sont en fait des oprateurs unaires. Le tableau 3-2 liste tous les oprateurs unaires nomms. Les oprateurs unaires nomms ont une prcdence suprieure celle de certains oprateurs binaires. Par exemple :
sleep 4 | 3;

customer_8566

84
Tableau 3-2. Oprateurs unaires nomms
-X (tests de fichiers) alarm caller chdir chroot cos defined delete do eval exists exit gethostbyname getnetbyname getpgrp getprotobyname glob gmtime goto hex int lc lcfirst length

Chapitre 3 Oprateurs unaires et binaires

localtime lock log lstat my oct ord quotemeta rand readlink ref require

return rmdir scalar sin sleep sqrt srand stat uc ucfirst umask undef

ne dort pas pendant 7 secondes ; il dort pendant 4 secondes puis prend la valeur de retour de sleep (typiquement zro) et la combine par OU avec 3, comme si lexpression avait des parenthses comme suit :
(sleep 4) | 3;

comparer avec :
print 4 | 3;

qui prend effectivement la valeur de 4 combin par OU avec 3 avant de lafficher (7 dans ce cas), comme sil tait crit :
print (4 | 3);

En effet, print est un oprateur de liste, et non un simple oprateur unaire. Une fois que vous saurez quels oprateurs sont des oprateurs de liste, vous naurez plus de problme pour distinguer les oprateurs de liste des oprateurs unaires. En cas de doute, vous pouvez toujours utiliser des parenthses pour transformer un oprateur unaire en fonction. Souvenez-vous, si a ressemble une fonction, cest une fonction. Une autre caractristique curieuse des oprateurs unaires nomms est que beaucoup dentre eux prennent $_ comme argument par dfaut, si vous ne leur en fournissez pas dautre. Cependant, si vous omettez largument et que ce qui suit ressemble au dbut dun argument, Perl va se tromper, car il attend un terme. Quand le caractre suivant du programme est lun de ceux lists au tableau 3-3, le tokeniseur de Perl renvoie diffrents types de token selon quil attend un terme ou un oprateur. Une erreur typique est donc :
next if length < 80;

o pour lanalyseur le < ressemble au dbut du symbole <> (un terme) au lieu du infrieur (un oprateur) auquel vous pensiez. Il nexiste pas vraiment de moyen darranger les choses tout en gardant Perl pathologiquement clectique. Si vous tes paresseux au point de ne pouvoir vous rsoudre taper les deux caractres $_, lune de ces instructions devrait faire laffaire :

customer_8566

Oprateurs unaires nomms et de test de fichier


Tableau 3-3. Caractres ambigus
Caractre + * / < . ? % & next next next next Oprateur Addition Soustraction Multiplication Division Infrieur , dcalage gauche Concatnation ?: Modulo &, && if length() < 80; if (length) < 80; if 80 > length; unless length >= 80; Terme Plus unaire Moins unaire *typeglob /motif/ <HANDLE>, <<END .3333 ?motif? %assoc &sousprogramme

85

Quand un terme est attendu, un signe moins suivi dune lettre seule sera toujours interprt comme un test de fichier. Un oprateur de test de fichier est un oprateur unaire qui prend commme argument un nom ou un handle de fichier, et teste le fichier associ pour savoir si une certaine proprit est vraie son sujet. Si largument est omis, il teste $_, sauf pour -t, qui teste STDIN. Sauf si cest indiqu autrement dans la documentation, il retourne 1 pour vrai et "" pour faux, ou la valeur indfinie si le fichier nexiste pas ou nest pas accessible. Les oprateurs de test de fichier actuellement implments sont lists au tableau 3-4. Tableau 3-4. Oprateurs de test de fichier
Oprateur -r -w -x -o -R -W -X -O -e -z -s -f -d -l Signification Fichier lisible par lUID/GID effectif. Fichier en criture pour lUID/GID effectif. Fichier excutable par lUID/GID effectif. Fichier possd par lUID/GID effectif. Fichier lisible par lUID/GID rel. Fichier en criture pour lUID/GID rel. Fichier excutable par lUID/GID rel. Fichier possd par lUID/GID rel. Le fichier existe. Fichier de taille nulle. Fichier de taille non nulle (renvoie la taille) Fichier simple. Le fichier est un rpertoire. Le fichier est un lien symbolique.

customer_8566

86

Chapitre 3 Oprateurs unaires et binaires

Tableau 3-4. Oprateurs de test de fichier (suite)


Oprateur -p -S -b -c -t -u -g -k -T -B -M -A -C Signification Le fichier est un tube nomm (FIFO). Le fichier est une socket. Fichier spcial de type bloc Fichier spcial de type caractre. Handle de fichier ouvert sur un tty. Fichier avec bit setuid. Fichier avec bit setgid. Fichier avec sticky bit. Fichier texte. Fichier binaire (le contraire de -T). ge du fichier (au dmarrage) en jours depuis sa modification. ge du fichier (au dmarrage) en jours depuis le dernier accs. ge du fichier (au dmarrage) en jours depuis le changement dinode.

Remarquez que -s/a/b/ ne fait pas une substitution ngative. -exp($foo) fonctionne cependant comme prvu ; seules les lettres isoles qui suivent un signe moins sont interprtes comme des tests de fichier. Linterprtation des oprateurs de test de permissions -r, -R, -w, -W, -x et -X est fonde uniquement sur le mode du fichier et les ID dutilisateur et de groupe de lutilisateur. Il peut y avoir dautres raisons pour lesquelles vous ne pouvez effectivement pas lire, crire ou excuter le fichier, comme les listes de contrle daccs dAFS (Andrew File System).4 Notez galement que pour le super utilisateur -r, -R, -w et -W renvoient toujours 1, et que -x et -X renvoient 1 si lun des bits dexcution est 1 dans le mode. Cest pourquoi les scripts lancs par le super utilisateur peuvent ncessiter un stat afin de connatre le vritable mode du fichier, ou bien remplacer temporairement lUID par autre chose. Les autres oprateurs de test de fichier se moquent de savoir qui vous tes. Nimporte qui peut utiliser le test pour les fichiers simples :
while (<>) { chomp; next unless -f $_; ... }

# ignore les fichiers "spciaux"

Les options -T et -B fonctionnent comme suit. Le premier bloc (plus ou moins) du fichier est examin la recherche de caractres inhabituels comme des code de contrle ou des octets donc le bit de poids fort est 1 (et qui nont pas lair dtre de lUTF-8). Si on trouve plus dun tiers doctets inhabituels, cest un fichier binaire ; sinon cest un fi-

4. Vous pouvez cependant ignorer la smantique intgre avec le pragma use filetest. Voir le chapitre 31, Modules de pragmas.

customer_8566

Oprateurs relationnels

87

chier texte. De mme, tout fichier dont le premier bloc contient le caractre ASCII NUL (\0) est considr comme binaire. Si -T ou -B est utilis sur un handle de fichier, le tampon dentre standard (standard I/O ou stdio ) en cours est examin, au lieu du premier bloc du fichier. -T et -B renvoient vrai sur un fichier vide, ou sur un fichier EOF (end-of-file : fin de fichier) quand on teste un handle. Comme Perl doit lire le fichier pour faire le test -T, vous devrez viter de vous en servir sur des fichiers qui risquent de bloquer ou de vous causer des ennuis. Cest pourquoi la plupart du temps, vous devrez tester avec un -f dabord, comme dans :
next unless -f $fichier && -T $fichier;

Si lon donne lun des tests de fichier (ou lun des oprateurs stat ou lstat) le handle spcial constitu dun soulign unique, cest la structure stat du dernier test de fichier (ou de loprateur stat) qui est utilise, conomisant ainsi un appel systme. (Cela ne marche pas avec -t, et il faudra vous souvenir que lstat et -l laissent dans la structure stat les valeurs pour le lien symbolique et non pour le fichier rel. De mme, -l _ sera toujours faux aprs un stat normal.) Voici quelques exemples :
print "Fait laffaire.\n" stat($fichier); print "En lecture\n" print "En criture\n" print "Excutable\n" print "Setuid\n" print "Setgid\n" print "Sticky\n" print "Texte\n" print "Binaire\n" if -r $a || -w _ || -x _;

if if if if if if if if

-r -w -x -u -g -k -T -B

_; _; _; _; _; _; _; _;

Les ges des fichiers donns par -M, -A et -C sont en jours (avec partie fractionnaire) depuis le moment o le script a commenc tourner. Cette date est stocke dans la variable spciale $^T ($BASETIME). Donc, si le fichier a t modifi depuis que le script a dmarr, vous obtiendrez une dure ngative. Remarquez que comme la plupart des dures (86 399 sur 86 400 en moyenne) sont fractionnaires, il est gnralement illusoire de tester lgalit avec un entier sans passer par la fonction int. Exemples :
next unless -M $fichier > .5; # &nouveaufichier if -M $fichier < 0; # &avertissemnt if int(-A) == 90; # # $^T = time; fichier vieux de plus de 12 heures fichier plus rcent que le processus fichier ($_) accd il y a 90 jours aujourdhui

Pour remettre la date courante la date de dmarrage du script, crivez :

Oprateurs relationnels
Perl possde deux classes doprateurs relationnels. Lune delles opre sur les valeurs numriques et lautre sur les valeurs de chane, comme indiqu au tableau 3-5.

customer_8566

88
Tableau 3-5. Oprateurs relationnels
Numrique > >= < <= Chane gt ge lt le

Chapitre 3 Oprateurs unaires et binaires

Signification Suprieur . Suprieur ou gal . Infrieur . Infrieur ou gal .

Ces oprateurs renvoient 1 pour vrai et "" pour faux. Notez que les oprateurs relationnels sont non-associatifs, ce qui signifie que $a < $b < $c provoquera une erreur de syntaxe. En labsence de dclaration de locales, les comparaisons de chanes sappuient sur lordre lexicographique ASCII/Unicode et, contrairement certains autres langages informatiques, les espaces finaux comptent pour la comparaison. Avec une dclaration de locale, lordre lexicographique spcifi par la locale est utilis. (Les mcanismes de tri fonds sur les locales peuvent plus ou moins bien interagir avec les mcanismes Unicode actuellement en cours de dveloppement.)

Oprateurs dgalit
Les oprateurs dgalit lists au tableau 3-6 ressemblent beaucoup aux oprateurs relationnels. Tableau 3-6. Oprateurs dgalit
Numrique == != <=> Chane eq ne cmp Signification gal . Diffrent de. Comparaison, avec rsultat sign.

Les oprateurs gal et diffrent renvoient 1 pour vrai et "" pour faux (exactement comme les oprateurs relationnels). Les oprateurs <=> et cmp renvoient -1 si loprande de gauche est infrieur celui de droite, 0 sil sont gaux et +1 si loprande de gauche est suprieur celui de droite. Bien que ces oprateurs semblent trs proches des oprateurs relationnels, ils ont un niveau de prcdence plus faible, et la syntaxe de $a < $b <=> $c < $d est donc valide. Pour des raisons videntes pour quiconque a vu Star Wars, loprateur <=> est aussi connu sous le nom doprateur vaisseau spatial (spaceship operator).

Oprateurs sur les bits


Comme C, Perl dispose des oprateurs ET, OU et OU-exclusif sur les bits : &, | et ^. Vous avez bien sr remarqu, aprs votre tude attentive du tableau au dbut de ce chapitre, que le ET sur les bits possde une prcdence suprieure aux autres ; nous avons trich pour tous les inclure dans cette discussion.

customer_8566

Oprateurs logique de type C ( court-circuit)

89

Ces oprateurs fonctionnent diffremment sur les valeurs numriques et sur les chanes. (Cest lun des rares cas o Perl fait une diffrence.) Si lun des oprandes est un nombre (ou a t utilis comme un nombre), les deux oprandes sont convertis en entiers, puis lopration sur les bits est effectue. Ces entiers font au moins 32 bits de long, mais peuvent faire 64 bits sur certaines machines. Limportant est quil existe une limite arbitraire impose par larchitecture de la machine. Si les deux oprandes sont des chanes (et nont pas t utiliss comme des nombres depuis leur dernire mise jour), les oprateurs font les oprations sur les bits sur les bits correspondants des deux chanes. Dans ce cas, il ny a aucune limite arbitraire, puisque les chanes ne sont pas limites en taille. Si lune des chanes est plus longue que lautre, on considre que la plus courte dispose dun nombre suffisant de bits 0 pour complter la diffrence. Par exemple, si vous faites un ET entre deux chanes :
"123.45" & "234.56"

vous obtenez une autre chane :


"020.44"

Mais si vous faites un ET sur une chane et un nombre :


"123.45" & 234.56

La chane est dabord convertie en nombre, ce qui donne :


123.45 & 234.56

Les nombres sont ensuite convertis en entiers :


123 & 234

ce qui donne 106. Remarquez que toutes les chanes de bits sont vraies ( moins de donner la chane 0 ). Cela signifie que si vous voulez vrifier si lun des octets rsultant est non nul, vous ne devrez pas crire ceci :
if ( "fred" & "\1\2\3\4" ) { ... }

mais cela :
if ( ("fred" & "\1\2\3\4") =~ /[^\0]/ ) { ... }

Oprateurs logique de type C ( court-circuit)


Comme C, Perl propose galement les oprateurs && (ET logique) et || (OU logique). Ils sont valus de gauche droite (&& ayant une prcdence lgrement suprieure celle de ||) pendant le test de vrit de linstruction. Ces oprateurs sont appels oprateurs court-circuit car ils dterminent la vrit de linstruction en valuant le plus petit nombre doprandes possible. Par exemple, si loprande gauche dun oprateur && est faux, loprande de droite ne sera jamais valu car le rsultat de loprateur sera faux quelle que soit la valeur de loprande de droite.
Exemple $a && $b $a || $b Nom Et Ou Rsultat $a si $a est faux, sinon $b. $a si $a est vrai, sinon $b.

customer_8566

90

Chapitre 3 Oprateurs unaires et binaires

Non seulement de tels courts-circuits font gagner du temps, mais ils sont frquemment utiliss pour contrler le f lux de lvaluation. Par exemple, un idiome courant en Perl est :
open(FILE, "monfichier") || die "Impossible douvrir monfichier: $!\n";

Dans ce cas, Perl value dabord la fonction open. Si sa valeur est vraie (car monfichier a t ouvert avec succs), lexcution de la fonction die nest pas ncessaire et est donc omise. Vous pouvez littralement lire Ouvre mon fichier ou meurs ! . Les oprateurs && et ||diffrent de ceux de C en ceci quau lieu de retourner 0 ou 1, ils renvoient la dernire valeur value. Dans le cas de ||, cela a le dlicieux effet de vous permettre de choisir la premire valeur vraie dune srie. Une manire raisonnablement portable de trouver le rpertoire personnel dun utilisateur pourrait donc tre :
$home = || || || $ENV{HOME} $ENV{LOGDIR} (getpwuid($<))[7] die "Vous tes SDF !\n";

Dun autre ct, comme largument de gauche toujours valu en contexte scalaire, vous ne pouvez pas vous servir de || afin choisir entre deux aggrgats pour une affectation :
@a = @b || @c; @a = scalar(@b) || @c; @a = @b ? @b : @c; # Ceci ne fait pas ce que vous voulez # car voici ce que cela veut dire. # En revanche cela marche bien.

Perl fournit galement des oprateurs and et or de moindre prcdence, que certains trouvent plus lisibles et qui ne vous forcent pas utiliser des parenthses sur les oprateurs de liste. Ils sont aussi court-circuit. Voir le tableau 1-1 pour la liste complte.

Oprateur dintervalle
Loprateur dintervalle .. comprend en fait deux oprateurs diffrents selon le contexte. Loprateur est bi-stable, comme un f lip-f lop lectronique, et mule loprateur dintervalle de ligne (virgule) de sed, awk et dautres diteurs. Chaque oprateur .. scalaire mmorise son propre tat boolen. Il est faux tant que son oprande de gauche est faux. Une fois que loprande de gauche est vrai, loprateur reste vrai jusqu ce que loprande de droite soit vrai, aprs quoi loprateur dintervalle redevient faux. Loprateur ne devient pas faux jusqu sa prochaine valuation. Il peut tester loprande de droite et devenir faux pendant la mme valuation que celle sur laquelle il est devenu vrai (comme loprateur de awk), mais renvoie vrai au moins une fois. Si vous ne voulez pas quil teste loprande de droite avant la prochaine valuation (comme loprateur de sed) utilisez simplement trois points (...) au lieu de deux. Pour les deux oprateurs .. et ..., loprande de droite nest pas valu tant que loprateur se trouve dans ltat faux, et loprande de gauche nest pas valu tant que loprateur est dans ltat vrai. La valeur renvoye est soit la chane vide pour faux soit un numro de squence (commenant 1) pour vrai. Le numro de squence est remis zro pour chaque oprateur dintervalle rencontr. La chane E0 est accole la fin du numro de squence final dans un intervalle, ce qui naffecte pas sa valeur numrique, mais vous donne quelque

customer_8566

Oprateur conditionnel

91

chose chercher si vous voulez exclure llment final. Vous pouvez exclure le point de dpart en attendant que le numro de squence soit plus grand que 1. Si lun des oprandes de .. est un littral numrique, cet oprande est implicitement compar la variable $., qui contient le numro de ligne courant de votre fichier dentre. Exemples :
if (101 .. 200) { print; } # imprime la deuxime centaine de lignes next line if (1 .. /^$/); # passe les enttes dun message s/^/> / if (/^$/ .. eof()); # cite le corps dun message

En contexte de liste, .. renvoie une liste de valeurs comptes partir de la valeur de gauche jusqu la valeur de droite (par incrments de un). Cela sert crire des boucles for (1..10) et pour faire des tranches de tableaux :
for (101 .. 200) { print; } @foo = @foo[0 .. $#foo]; @foo = @foo[ -5 .. -1]; # affiche 101102...199200 # un no-op coteux # la tranche des 5 derniers lments

Si la valeur de gauche est suprieure celle de droite, une liste vide est renvoye. (Pour construire une liste en ordre inverse, voir loprateur reverse.) Si ses oprandes sont des chanes, loprateur dintervalle emploie lalgorithme dautoincrmentation magique vu prcdemment.5 Vous pouvez donc crire :
@alphabet = (A .. Z);

pour obtenir toutes les lettres de lalphabet (latin), ou :


$hexdigit = (0 .. 9, a .. f)[$nombre & 15];

pour obtenir un chiffre hexadcimal, ou :


@z2 = (01 .. 31); print $z2[$jour];

pour obtenir des dates avec un zro en tte. Vous pouvez galement crire :
@combis = (aa .. zz);

pour obtenir toutes les combinaisons de deux lettres minuscules. Attention cependant quelque chose comme :
@grossescombis = (aaaaaa .. zzzzzz);

car cela va ncessiter beaucoup de mmoire. Pour tre prcis, il faudra de lespace pour stocker 308 915 776 scalaires. Esprons que vous avez une grosse partition de swap. Vous devriez vous intresser une approche itrative.

Oprateur conditionnel
Loprateur ?: est le seul oprateur ternaire, comme en C. On lappelle souvent loprateur conditionnel, car il fonctionne comme un if-then-else, except quil peut tre inclus sans problme dans dautres expressions et fonctions, car cest une expression et non une instruction. En tant quoprateur ternaire, ses deux lments sparent trois expressions : COND ? EXPR_SI_VRAI : EXPR_SI_FAUX

5. Si la valeur finale spcifie nest pas dans la squence que lincrmentation magique produirait, la squence continue jusqu ce que le prochain lment soit plus long que la valeur finale.

customer_8566

92

Chapitre 3 Oprateurs unaires et binaires

Si la condition COND est vrai, seule lexpression EXPR_SI_VRAI est value, et la valeur de cette expression devient la valeur de toute lexpression. Sinon, seule lexpression EXPR_SI_FAUX est value, et sa valeur devient celle de toute lexpression. Le contexte scalaire ou de liste se propage vers le deuxime ou le troisime argument, selon celui qui est slectionn. (Le premier argument est toujours en contexte scalaire, puisque cest une condition.)
$a = $ok ? $b : $c; # donne un scalaire @a = $ok ? @b : @c; # donne un tableau $a = $ok ? @b : @c; # donne le nombre dlments dun tableau

Vous verrez souvent loprateur conditionnel inclus dans des listes de valeurs formater avec printf, car personne na envie de dupliquer une instruction complte juste pour basculer entre deux valeurs proches.
printf "Jai %d chameau%s.\n", $n, $n <= 1 ? "" : "x";

La prcdence de ?: est opportunment plus grande que celle de la virgule, mais infrieure celle de la plupart des oprateurs que vous utiliserez lintrieur (comme == dans cet exemple) ; vous naurez donc gnralement pas utiliser de parenthses. Mais vous pouvez ajouter des parenthses pour clarifier, si vous voulez. Pour les oprateurs conditionnels embots lintrieur de la partie EXPR_SI_VRAI dautres oprateurs conditionnels, nous vous suggrons de de faire des sauts de ligne et dindenter comme sil sagisait dinstruction if ordinaires :
$bissextile = $annee % 4 == 0 ? $annee % 100 == 0 ? $annee % 400 == 0 ? 1 : 0 : 1 : 0;

Pour les conditions imbriques dans des parties EXPR_SI_FAUX doprateurs conditionnels prcdents, vous pouvez faire quelque chose dquivalent :
$bissextile $annee ? : = % 4 0 $annee % 100 ? 1 : $annee % 400 ? 0 : 1;

mais il est habituellement prfrable daligner verticalement toutes les COND et les EXPR_SI_VRAI :
$bissextile $annee $annee $annee = % 4 ? 0 : % 100 ? 1 : % 400 ? 0 : 1;

customer_8566

Oprateurs daffectation

93

Mme des structures assez encombres peuvent sclaircir en alignant les points dinterrogation et les deux-points :
printf "Oui, $i18n eq $i18n eq $i18n eq jaime mon "anglais" "allemand" "japonais" livre du %s!\n", ? "camel" : ? "Kamel" : ? "\x{99F1}\x{99DD}" : "chameau"

Vous pouvez affecter loprateur conditionnel6 si le deuxime et le troisime arguments sont tous les deux des lvalueslgales (cest--dire quon peut leur affecter une valeur), et que tous deux sont soit des scalaires, soit des listes (sinon Perl ne saura pas quel contexte fournir la partie droite de laffectation) :
($a_ou_b ? $a : $b) = $c; # donne la valeur de $c soit $a, soit $b

Souvenez-vous que loprateur conditionnel lie encore plus fort que les multiples oprateurs daffectation. Cest habituellement ce que vous voulez (voir lexemple $bissextile plus haut, par exemple), mais vous ne pourrez pas obtenir leffet inverse sans parenthses. Lutilisation daffectations dans un oprateur conditionnel vous attirera des ennuis, et vous risquez mme de ne pas avoir derreur lanalyse car loprateur conditionnel peut tre analys comme une lvalue. Par exemple, vous pourriez crire ceci :
$a % 2 ? $a += 10 : $a += 2 # FAUX

Mais ce serait analys comme cela :


(($a % 2) ? ($a += 10) : $a) += 2

Oprateurs daffectation
Perl reconnat les oprateurs daffectation de C, et fournit galement les siens. Il y en a un certain nombre :
= **= += -= .= *= /= %= x= &= |= ^= <<= >>= &&= ||=

Chaque oprateur ncessite une lvalue cible (typiquement une variable ou un lment de tableau) sa gauche et une expression sa droite. Pour loprateur daffectation simple : CIBLE = EXPR La valeur de EXPR est stocke dans la variable ou lendroit dsign par CIBLE. Pour les autres oprateurs, Perl value lexpression : CIBLE OP= EXPR comme sil tait crit : CIBLE = CIBLE OP EXPR
6. Cela ne garantit pas une amlioration de la lisibilit de votre programme. Mais a peut servir construire des participations sympas pour un concours de Perl assombri (Obfuscated Perl Contest).

customer_8566

94

Chapitre 3 Oprateurs unaires et binaires

Cest un bon moyen mnmotechnique, mais il est trompeur, et de deux manires. Dabord les oprateurs daffectation sont analyss au niveau de prcdence des affectations ordinaires, quelle que soit la prcdence que loprateur OP aurait eu par lui-mme. Ensuite, CIBLE nest valu quune seule fois. Habituellement cela na aucune importance, sauf en cas deffets secondaires, comme pour une auto-incrmentation.
$var[$a++] += $valeur; $var[$a++] = $var[$a++] + $valeur; # $a is increment une fois # $a is increment deux fois

la diffrence de C, loprateur daffectation produit une lvalue valide. Modifier une affectation revient faire laffectation puis modifier la variable laquelle on vient daffecter une valeur. Cela peut servir modifier une copie de quelque chose, comme ceci :
($tmp = $global) += $constante;

qui est quivalent :


$tmp = $global + $constante;

De mme :
($a += 2) *= 3;

est quivalent :
$a += 2; $a *= 3;

Ce nest pas tellement utile, mais voici un idiome frquent :


($nouveau = $ancien) =~ s/toto/titi/g;

Dans tous les cas, la valeur de laffectation est la nouvelle valeur de la variable. Comme les oprateurs daffectations sont associatifs de droite gauche, cela peut servir affecter la mme valeur plusieurs variables, comme dans :
$a = $b = $c = 0;

qui affecte 0 $c et le rsultat de cette opration (toujours 0) $b, puis le rsultat de (toujours 0) $a. Les affectations de listes ne se font quavec loprateur daffectation simple, =. Dans un contexte de liste, une affectation de liste retourne la liste des nouvelles valeurs, tout comme laffectation scalaire. En contexte scalaire, une affectation de liste renvoie le nombre de valeurs qui taient disponibles droite de laffectation, comme indiqu au chapitre 2, Composants de Perl. Cela sert pour tester les fontions qui renvoient une liste vide quand elles chouent (ou finissent par chouer), comme dans :
while (($cle, $valeur) = each %gloss) { ... } next unless ($dev, $ino, $mode) = stat $fichier;

Oprateurs virgule
Le , binaire est loprateur virgule. En contexte scalaire, il value son argument de gauche en contexte vide, jette le rsultat, puis value son argument de droite et retourne cette valeur. Exactement comme loprateur virgule de C. Par exemple :
$a = (1, 3);

customer_8566

Oprateurs de liste (vers la droite)

95

affecte 3 $a. Attention ne pas confondre son utilisation en contexte scalaire avec son utilisation en contexte de liste. Dans un contexte de liste, une virgule est juste le sparateur des arguments de la liste et il insre ses deux arguments dans la LISTE. Il ne jette aucune valeur. Par exemple, si vous modifiez lexemple prcdent en :
@a = (1, 3);

vous construisez une liste de deux lments, tandis que :


atan2(1, 3);

appelle la fonction atan2 avec deux arguments. La plupart du temps, le digramme => est juste un synonyme pour loprateur virgule. Il sert documenter les arguments apparis. Il force galement linterprtation comme chane de tout identificateur plac sa gauche.

Oprateurs de liste (vers la droite)


La partie droite dun oprateur de liste commande tous les arguments de loprateur de liste, qui sont spars par des virgules ; donc la prcdence dun oprateur de liste est plus faible que celle de la virgule, si vous regardez vers la droite. Une fois quun oprateur de liste commence avaler des arguments spars par des virgules, les seules choses qui larrtent sont les tokens qui terminent lexpression toute entire (comme les points-virgules ou les modificateurs dinstructions) ou les tokens qui terminent la sousexpression en cours (comme les parenthses ou les crochets fermants) ou les oprateurs logiques de faible prcdence dont nous aller parler tout de suite.

And, or, not et xor logiques


Perl fournit les oprateurs and, or, et not comme alternatives de moindre prcdence &&, ||, et !. Le comportement de ces oprateurs est identique en particulier, and et or court-circuitent comme leurs alter-egos, ce qui leur donne leur utilit non seulement pour les expressions logiques, mais aussi pour le contrle du f lux dvaluation. Comme la prcdence de ces oprateurs est beaucoup plus basse que celle des oprateurs emprunts C, vous pouvez les utiliser en toute scurit aprs un oprateur de liste, sans quil soit besoin de parenthses.
unlink "alpha", "beta", "gamma" or enrage(), next LIGNE;

Avec les oprateurs issus de C, vous auriez d lcrire comme ceci :


unlink("alpha", "beta", "gamma") || (enrage(), next LIGNE);

Mais vous ne pouvez pas simplement remplacer toutes les occurences de || par or. Supposons que vous changiez ceci :
$xyz = $x || $y || $z;

en cela :
$xyz = $x or $y or $z; # FAUX

customer_8566

96

Chapitre 3 Oprateurs unaires et binaires

Cela ne ferait pas du tout la mme chose ! La prcdence de laffectation est suprieure celle de or mais plus basse que celle de ||, donc on affecterait toujours $x $xyz pour ensuite seulement faire les or. Pour obtenir le mme rsultat quavec ||, vous devrez crire :
$xyz = ( $x or $y or $z );

La morale de cette histoire, cest quil faut toujours apprendre les rgles de prcdence (ou utiliser les parenthses) quels que soient les oprateurs logiques que vous utilisez. Il existe galement un xor logique qui na pas dquivalent exact en C ou en Perl, puisque le seul autre oprateur OU-exclusif (^) travaille sur les bits. Loprateur xor ne peut pas court-circuiter, car les deux cts doivent tre valus. Le meilleur quivalent de $a xor $b est peut-tre !$a != !$b. On pourrait galement crire !$a ^ !$b ou mme $a ? !$b : !!$b, bien sr. Lessentiel est que $a et $b doivent tous les deux tre valus comme vrais ou faux dans un contexte boolen, et loprateur sur les bits existant nen fournit pas sans quon ly aide.

Oprateurs C manquant en Perl


Voici ce que C a et que Perl na pas : & unaire Loprateur adresse-de. Loprateur \ de Perl (qui fournit une rfrence) occupe la mme niche cologique :
$ref_var = \$var;

Mais les rfrences de Perl sont plus sres que les pointeurs de C. * unaire Loprateur de drfrencement dadresse. Comme Perl ne connat pas les adresses, il na pas besoin de les drfrencer. En revanche, Perl a des rfrences et ce sont donc les caractres de prfixe variable qui servent doprateurs de drfrence, tout en indiquant le type : $, @, % et &. tonnament, il existe bien un oprateur * de drfrencement, mais comme * est le drle de caractre indiquant un typeglob, vous ne lutiliserez pas ainsi. (TYPE) Loprateur de transtypage. De toute faon, personne naime se faire transtyper.

customer_8566

Instructions et dclarations
Un programme Perl consiste en une squence de dclarations et dinstuctions. Une dclaration peut-tre place partout o une instruction peut ltre, mais son effet premier se produit la compilation. Certaines dclarations jouent un double rle en tant quinstructions, mais la plupart sont totalement transparentes lexcution. Aprs la compilation, la squence dinstructions principale est excute une seule fois. Contrairement beaucoup de langages de programmation, Perl nimpose pas de dclarer explicitement les variables ; elles se mettent exister leur premire utilisation, que vous les ayez dclares ou non. Si vous essayez dutiliser la valeur dune variable laquelle aucune valeur na jamais t affecte, elle est traite silencieusement comme si elle contenait 0 si vous vouliez un nombre, comme "" si vous vouliez une chane ou simplement comme une valeur fausse si vous vouliez une valeur logique. Si vous prfrez tre averti de lutilisation de valeurs non dfinies comme si elles taient de vritables chanes ou nombres, ou mme traiter cette utilisation comme une erreur, la dclaration use warnings sen chargera ; voir la section Pragmas la fin de ce chapitre. Cependant, si vous prfrez, vous pouvez ventuellement dclarer vos variables, en utilisant soit my ou our avant le nom de variable. Vous pouvez mme faire quutiliser une variable non dclare soit une erreur. Cest bien de vouloir de la discipline, encore fautil la demander. Normalement, Perl ne sintresse pas vos habitudes de programmation ; mais avec la dclaration use strict, lutilisation de variables non dclares est dtecte la compilation. De nouveau, voir la section Pragmas.

Instructions simples
Une instruction simple est une expression value pour ses effets secondaires. Toute instruction simple doit se terminer par un point-virgule, sauf si cest la dernire instruction dun bloc. Dans ce cas, le point-virgule est optionnel Perl sait que vous en avez fini avec cette instruction, puisque vous avez fini le bloc. Mais mettez quand mme le pointvirgule sil sagit dun bloc multiligne, car vous pourriez bien ajouter une autre ligne par la suite.

customer_8566

98

Chapitre 4 Instructions et dclarations

Bien que des oprateurs comme eval {}, do {} et sub {} ressemblent des instructions composes, en fait ce nen sont pas. Certes, ils permettent davoir plusieurs instructions lintrieur, mais cela ne compte pas. Vus de lextrieur, ces oprateurs sont juste des termes dans une expression ; cest pourquoi ils ncessitent un point-virgule explicite quand ils sont utiliss comme dernier lment dune instruction. Toute instruction simple peut tre optionnellement suivi dun modificateur unique, juste avant le point-virgule final (ou la fin de bloc). Les modificateurs possibles sont :
if EXPR unless EXPR while EXPR until EXPR foreach LISTE

Les modificateurs if et unless fonctionnent comme peuvent sy attendre les anglophones :


$trash->take(out) if $you_love_me; # sors la poubelle si tu maimes shutup() unless $you_want_me_to_leave; # tais-toi, sauf si tu veux que # je men aille

Les modificateurs while et until sont valus de faon rpte. Comme notre lectorat anglophone pouvait sy attendre, un modificateur while excute lexpression tant que sa propre expression reste vraie, tandis quun modificateur until continue de sexcuter tant quelle reste fausse :
$expression++ while -e "$file$expression"; kiss(me) until $I_die; # embrasse-moi jusqu la mort

Le modificateur foreach (aussi orthographi for) est valu une fois par lment de sa LISTE, $_ tant un alias de llment courant :
s/java/perl/ for @curriculum; print "champ: $_\n" foreach split /:/, $ligne;

Les modificateurs while et until ont la smantique usuelle des boucles while (la condition est value en premier), sauf quand ils sappliquent un doBLOC (ou linstruction maintenant dprcie doSUBROUTINE), auquel cas le bloc sexcute une fois avant que la condition soit value. Cela vous permet dcrire des boucles comme :
do { $ligne = <STDIN>; ... } until $ligne eq ".\n";

Voyez aussi les trois diffrentes entres de do au chapitre 29, Fonctions. Remarquez galement que les oprateurs de contrle de boucle dcrits plus loin ne fonctionnent pas dans cette construction, car les modificateurs de boucles ne prennent pas dtiquette. Vous pouvez toujours placer un bloc supplmentaire autour pour terminer plus tt, ou lintrieur pour itrer avant la fin de la boucle, comme cela est dcrit dans la section Blocs simples. Ou bien vous pourriez crire une vraie boucle avec plusieurs commandes de contrle de boucle lintrieur. propos de vraies boucles, nous allons maintenant parler des instructions composes.

customer_8566

Instructions composes

99

Instructions composes
On appelle bloc une squence dinstructions dfinie dans une porte1. Parfois la porte stend sur un fichier tout entier, comme par exemple un fichier appel avec require ou le fichier contenant votre programme principal. Dautres fois la porte a ltendue dune chane value avec eval. Mais en gnral, un bloc est entour daccolades ({}). Quand nous parlons de porte, cela signifie nimporte laquelle de ces trois possibilits. Quand nous voudrons dire un bloc entour daccolades, nous emploierons le terme BLOC. Les instructions composes sont construites partir dexpressions et de BLOC. Les expressions sont construites partir de termes et doprateurs. Dans nos descriptions syntaxiques, nous utiliserons le mot EXPR pour indiquer un emplacement o vous pouvez utiliser nimporte quelle expression scalaire. Pour indiquer une expression value en contexte de liste, nous dirons LISTE. Les constructions suivantes peuvent tre utilises pour contrler lexcution de BLOC de faon conditionnelle ou rpte. (Ltiquette LABEL est optionnelle.)
if if if if (EXPR) (EXPR) (EXPR) (EXPR)

BLOC BLOC else BLOC BLOC elsif (EXPR) BLOC ... BLOC elsif (EXPR) BLOC ... else BLOC BLOC BLOC else BLOC BLOC elsif (EXPR) BLOC ... BLOC elsif (EXPR) BLOC ... else BLOC

unless unless unless unless

(EXPR) (EXPR) (EXPR) (EXPR)

LABEL while (EXPR) BLOC LABEL while (EXPR) BLOC continue BLOC LABEL until (EXPR) BLOC LABEL until (EXPR) BLOC continue BLOC LABEL for (EXPR; EXPR; EXPR) BLOC LABEL foreach (LISTE) BLOC LABEL foreach VAR (LISTE) BLOC LABEL foreach VAR (LISTE) BLOC continue BLOC LABEL BLOC LABEL BLOC continue BLOC Remarquez qu linverse de C et de Java, elles sont dfinies en termes de BLOC, et non dinstructions. Cela signifie que les accolades sont obligatoires ; les instructions isoles ne sont pas autorises. Si vous voulez crire des conditions sans accolades, il y a plusieurs manires de le faire. Les lignes suivantes font toutes la mme chose :
1. Les portes et les espaces de nommage sont dcrits au chapitre 2, Composants de Perl, la section Noms.

customer_8566

100
unless (open(TOTO, $toto)) if (!open(TOTO, $toto))

Chapitre 4 Instructions et dclarations


{ die "Impossible douvrir $toto: $!" } { die "Impossible douvrir $toto: $!" } unless open(TOTO, $toto); if !open(TOTO, $toto);

die "Impossible douvrir $toto: $!" die "Impossible douvrir $toto: $!" open(TOTO, $toto) open TOTO, $toto

|| die "Impossible douvrir $toto: $!"; or die "Impossible douvrir $toto: $!";

Nous avons tendance prfrer les deux dernires dans la plupart des cas. Elles sont plus lisibles que les autres, en particulier la version or die . Avec || vous devez vous habituer utiliser les parenthses religieusement, tandis quavec la version or, ce nest pas grave de les oublier. Mais la principale raison pour laquelle nous prfrons les dernires versions est quelles mettent la partie la plus importante de linstruction au dbut de la ligne, l o vous la verrez le mieux. La gestion derreur est repousse vers la droite, o vous navez pas besoin dy faire attention, sauf si vous le voulez2. Et si vous tabulez tous vos tests or die la mme position droite de chaque ligne, cest encore plus facile lire :
chdir $dir open TOTO, $fichier @lines = <TOTO> close TOTO or or or or die die die die "chdir $dir: $!"; "open $fichier: $!"; "$fichier est vide ?"; "close $fichier: $!";

Instructions if et unless
Linstruction if est simple. Comme les BLOCs sont dlimits par des accolades, il ny jamais dambigut pour savoir quel if en particulier un else ou un elsif est li. Dans une squence donne de BLOCs if/elsif/else, seul le premier dont la condition est vraie est excut. Si aucune des conditions nest vraie, alors le BLOC else, sil existe, est excut. Cest en gnral une bonne ide de mettre un else la fin dune chane de elsif, afin de se prmunir contre un cas oubli. Si vous utilisez unless la place de if, le sens du test est invers. Cest--dire que :
unless ($x == 1) ...

est quivalent :
if ($x != 1) ...

ou au plus laid :
if (!($x == 1)) ...

La porte dune variable dclare dans la condition de contrle stend de sa dclaration jusqu la fin de linstruction conditionnelle, y compris tous les elsif et lventuelle clause else finale, mais pas plus loin :
if ((my $couleur = <STDIN>) =~ /rouge/i) { $valeur = 0xff0000; }
2. Tout comme pour cette note.

customer_8566

Instructions de boucle

101

elsif ($couleur =~ /vert/i) { $valeur = 0x00ff00; } elsif ($couleur =~ /bleu/i) { $valeur = 0x0000ff; } else { warn "`$couleur : composante RGB inconnue, le noir est slectionn\n"; $valeur = 0x000000; }

Aprs le else, la variable $couleur est hors de porte. Si vous voulez que sa porte stende plus loin, dclarez la variable plus tt.

Instructions de boucle
Dans leur syntaxe formelle, toutes les instructions de boucle comportent un LABEL (ou tiquette) facultatif. (Vous pouvez mettre une telle tiquette sur nimporte quelle instruction, mais cela a une signification spciale pour les boucles.) Sil est prsent, le label consiste en un identificateur suivi de deux-points. Il est courant dcrire ltiquette en majuscules pour viter tout conf lit avec des mots rservs et les faire mieux ressortir. Bien que Perl ne se pose pas de problme si vous utilisez un label qui a dj une signification comme if ou open, vos lecteurs risquent de se tromper.

Instructions while et until


Linstruction while excute le bloc tant que EXPR est vraie. Si le mot while est remplac par until, le sens du test est invers ; cest--dire quil excute le bloc tant que EXPR est fausse. La condition est cependant toujours teste avant la premire itration. Les instructions while ou until comportent un bloc supplmentaire facultatif : le bloc continue. Ce bloc est excut chaque fois que lon achve litration, soit en sortant la fin du premier bloc, soit par un next explicite (next est un oprateur de contrle de boucle qui passe litration suivante). En pratique, le bloc continue nest pas trs utilis, mais il est prsent afin de pouvoir dfinir rigoureusement la boucle for dans la section qui suit. Contrairement la boucle for que nous allons voir dans un moment, une boucle while ne localise jamais implicitement de variables dans sa condition de test. Cela peut avoir d intressantes consquences quand des boucles while utilisent des variables globales comme variables de boucle. En particulier, consultez la section Oprateur de lecture de ligne (Angle) au chapitre 2 pour voir comment une affectation implicite la variable globale $_ peut se produire dans certaines boucles while, ainsi quun exemple de gestion de ce problme en localisant explicitement $_. Il est cependant prfrable de dclarer les autres variables de boucle avec my, comme dans lexemple suivant. Une variable dclare dans la condition de test dune instruction while ou dun until est visible seulement dans le ou les blocs pilots par ce test. Sa porte ne stend pas audel. Par exemple :
while (my $ligne = <STDIN>) {

customer_8566

102
$ligne = lc $ligne; } continue { print $ligne; # toujours visible } # $ligne maintenant hors de porte

Chapitre 4 Instructions et dclarations

Ici, la porte $ligne stend de sa dclaration dans lexpression de contrle lensemble de la boucle, y compris le bloc continue, mais pas au-del. Si vous voulez que sa porte stende plus loin, dclarez la variable avant la boucle.

Boucles for
La boucle for en trois parties comporte trois expressions spares par des points-virgules entre ses parenthses. Ces expressions sont respectivement linitialisation, la condition et la r-initialisation de la boucle. Ces trois expressions sont optionnelles (mais pas les points-virgules) ; si la condition est omise, elle est toujours vraie. La boucle for peut tre dfinie dans les termes de la boucle while correspondante. Ce qui suit :
LABEL: for (my $i = 1; $i <= 10; $i++) { ... }

est donc identique :


{ my $i = 1; LABEL: while ($i <= 10) { ... } continue { $i++; } }

sinon quil ny a pas vraiment de bloc extrieur. (Nous lavons juste mis l pour montrer les limites du my.) Si vous voulez itrer deux variables simultanment, il vous suffit de sparer les expressions parallles par des virgules :
for ($i = 0, $bit = 0; $i < 32; $i++, $bit <<= 1) { print "Le bit $i is est 1\n" if $mask & $bit; } # les valeurs de $i et $bit persistent aprs la boucle

Ou bien dclarer ces variables comme visibles seulement lintrieur de la boucle for :
for (my ($i, $bit) = (0, 1); $i < 32; $i++, $bit <<= 1) { print "Le bit $i is est 1\n" if $mask & $bit; } # les $i et $bit de la boucle sont maintenant hors de porte

customer_8566

Instructions de boucle

103

En plus des boucles habituelles sur les indices de tableaux, for a dautres applications intressantes. Il na mme pas besoin dune variable de boucle explicite. Voici un exemple permettant dviter le problme que vous rencontrez en testant explicitement la fin de fichier sur un descripteur de fichier interactif, provoquant ainsi le blocage du programme.
$sur_un_tty = -t STDIN && -t STDOUT; sub prompt { print "yes? " if $sur_un_tty } for ( prompt(); <STDIN>; prompt() ) { # fait quelque chose }

Une autre application traditionnelle pour le for en trois parties vient du fait que les trois expressions sont optionnelles et que la condition par dfaut est vraie. Si vous omettez les trois expressions, vous obtenez une boucle infinie :
for (;;) { ... }

Ce qui est exactement quivalent :


while (1) { ... }

Si la notion de boucle infinie vous inquite, nous devrions souligner que vous pouvez toujours sortir de la boucle quand vous voulez avec un oprateur de contrle explicite de boucle comme last. Bien sr, si vous crivez le code de contrle dun missile de croisire, vous naurez jamais vraiment besoin de sortir de la boucle. Elle se terminera automatiquement au moment opportun.3

Boucles foreach
La boucle foreach parcourt une liste de valeurs en affectant tour tour chaque lment de la liste la variable de contrle (VAR) :
foreach VAR (LISTE) { ... }

Le mot-cl foreach est juste un synonyme du mot-cl for, vous pouvez donc utiliser au choix for et foreach, selon lequel vous trouvez le plus lisible dans une situation donne. Si VAR est omis, la variable globale $_ est utilise. (Ne vous inquitez pas Perl distingue facilement for (@ARGV) de for ($i=0; $i<$#ARGV; $i++), car ce dernier contient des points-virgules.) Voici quelques exemples :
$somme = 0; foreach $valeur (@tableau) { $somme += $valeur } for $decompte (10,9,8,7,6,5,4,3,2,1,BOUM) { # compte rebours print "$decompte\n"; sleep(1); }
3. Cest--dire que les retombes de la boucle ont tendance se produire automatiquement.

customer_8566

104
for (reverse BOUM, 1 .. 10) { print "$_\n"; sleep(1); }

Chapitre 4 Instructions et dclarations


# pareil

for $champ (split /:/, $data) { print "Le champ contient : $champ\n"; } foreach $cle (sort keys %hash) { print "$cle => $hash{$cle}\n"; }

# toute expression de LISTE

Le dernier reprsente la manire classique dafficher les valeurs dun hachage dans lordre des cls. Consultez les entres keys et sort au chapitre 29 pour des exemples plus labors. Il nexiste aucune manire de savoir o vous en tes dans une liste avec foreach. Vous pouvez comparer des lments adjacents en vous souvenant du prcdent dans une variable, mais il faudra parfois vous contenter dcrire une boucle for en trois parties avec des indices. Aprs tout, cet autre for est justement l pour a. Si LISTE est entirement constitue dlments auxquels on peut affecter une valeur (cest--dire de variables, pas dune numration de constantes), vous pouvez modifier chacune de ces variables en modifiant VAR lintrieur de la boucle. Cela provient du fait que la variable dindice de la boucle foreach est un alias implicite de chaque lment de la liste sur laquelle vous bouclez. Vous pouvez non seulement modifier un tableau dun coup, mais galement plusieurs tableaux ou hachages dans une seule liste :
foreach $paye (@salaires) { $paye *= 1.08; } for (@noel, @paques) { s/pt/foie gras/; } s/pt/foie gras/ for @noel, @paques; # une augmentation de 8%

# change le menu

# idem

for ($scalaire, @tableau, values %hash) { s/^\s+//; # retire les espaces initiaux s/\s+$//; # retire les espaces finaux }

La variable de boucle est valide uniquement dans la porte dynamique ou lexicale de la boucle et sera implicitement lexicale si la variable a t prcdemment dclare avec my. Cela la rend invisible toute fonction dfinie en dehors de la porte lexicale de la variable, mme si elle est appele depuis cette boucle. Cependant si aucune dclaration lexicale nest porte, la variable de boucle sera une variable globale localise ( porte dynamique) ; cela permet aux fonctions appeles depuis la boucle daccder cette variable. Dans tous les cas, la valeur quavait la variable localise avant la boucle sera restaure la sortie de la boucle. Si vous prfrez, vous pouvez dclarer explicitement quel type de variable (lexicale ou globale) utiliser. Ceux qui maintiennent votre code sauront plus facilement ce qui se

customer_8566

Instructions de boucle

105

passe ; sinon, ils devront remonter la chane des portes successives la recherche dune dclaration pour deviner de quelle variable il sagit :
for my $i (1 .. 10) { ... } for our $Tick (1 .. 10) { ... } # $i toujours lexicale # $Tick toujours globale

Quand une dclaration accompagne la variable de boucle, lcriture courte for est toujours prfrable foreach, car cela se lit mieux en anglais.4 Voici comment un programmeur C ou Java pourrait dabord penser crire un algorithme donn en Perl :
for ($i = 0; $i < @tab1; $i++) { for ($j = 0; $j < @tab2; $j++) { if ($tab1[$i] > $tab2[$j]) { last; # Impossible daller la boucle externe. :-( } $tab1[$i] += $tab2[$j]; } # voici o ce last memmne }

Mais voici comment un programmeur Perl expriment pourrait lcrire :


WID: foreach $ceci (@tab1) { JET: foreach $cela (@tab2) { next WID if $ceci > $cela; $ceci += $cela; } }

Vous voyez combien ctait simple en Perl idiomatique ? Cest plus propre, plus sr et plus rapide. Cest plus propre car il y a moins de bruit. Cest plus sr car si du code est ajout par la suite entre les boucles interne et externe, ce code ne sera pas accidentellement excut, car next (expliqu plus loin) reboucle sur la boucle externe Mais vous codez comme vous prfrez. TMTOWTDI. Comme linstruction while, linstruction foreach peut aussi avoir un bloc continue. Cela vous permet dexcuter un bout de code la fin de chaque itration de boucle, que vous en soyez arriv l par le cours normal des vnements ou par un next.

Contrle de boucle
Nous avons dj mentionn que vous pouviez mettre un LABEL sur une boucle pour lui donner un nom. Ltiquette identifie la boucle pour les oprateurs de contrle de boucle next, last et redo. Le LABEL dsigne la boucle toute entire, pas seulement le dbut de celle-ci. Une commande de contrle de boucle ne va pas au LABEL lui-mme. Pour lordinateur ltiquette aurait aussi bien pu tre place la fin de la boucle. Mais il semble que les gens prfrent les tiquettes au dbut.

4. NdT : Dune manire gnrale, vous avez maintenant remarqu quil est utile davoir des notions danglais si lon veut profiter des subtilits de Perl (et de CPAN).

customer_8566

106

Chapitre 4 Instructions et dclarations

Les boucles sont typiquement nommes daprs les lments quelles manipulent chaque itration. Cela se combine bien avec les oprateurs de contrle de boucle, qui sont conus pour se lire comme de langlais quand ils sont utiliss avec une tiquette aproprie et un modificateur dinstruction. La boucle typique traite des lignes, donc ltiquette de boucle typique est LINE: ou LIGNE: et loprateur de contrle de ligne typique ressemble ceci :
next LIGNE if /^#/; last LABEL next LABEL redo LABEL # supprime les commentaires

La syntaxe des oprateurs de contrle de boucle est :

Le LABEL est optionnel ; sil est omis, loprateur se rfre la boucle englobante la plus interne. Mais si vous voulez sauter plus dun niveau, vous devez utiliser un LABEL pour dsigner la boucle sur laquelle agir. Ce LABEL na pas besoin dtre dans la mme porte lexicale que loprateur de contrle, mais cest probablement prfrable. En fait, le LABEL peut tre nimporte o dans la porte dynamique. Si cela vous force sortir dun eval ou dun sous-programme, Perl met un avertissement (sur demande). Tout comme vous pouvez avoir autant de return que vous voulez dans une fonction, vous pouvez avoir autant doprateurs de contrle de boucle que vous voulez dans une boucle. Cela na pas tre considr comme mauvais ou pas cool. Aux dbuts de la programmation structure, certaines personnes insistaient sur le fait que les boucles et les sous-programmes ne devaient avoir quune entre et quune sortie. La notion dentre unique est toujours une bonne ide, mais la notion de sortie unique a conduit lcriture de beaucoup de code artificiel. La programmation consiste principalement parcourir des arbres de dcision. Un arbre de dcision commence naturellement par une racine unique mais se termine par de nombreuses feuilles. crivez votre code avec le nombre de sorties de boucle (et de retours de fonction) qui est naturel pour le problme que vous essayez de rsoudre. Si vous avez dclar vos variables dans des portes raisonnables, tout sera automatiquement nettoy le moment venu, quelle que soit la manire dont vous quittez le bloc. Loprateur last sort immdiatement de la boucle en question. Le bloc continue, sil existe, nest pas excut. Lexemple suivant sjecte de la boucle la premire ligne blanche :
LIGNE: while (<STDIN>) { last LIGNE if /^$/; ... } # sort quand lentte de mail est fini

Loprateur next passe le reste de litration courante de la boucle et commence la suivante. Sil existe une clause continue sur la boucle, elle est excute juste avant que la condition soit r-value, exactement comme la troisime partie dune boucle for. Elle peut donc servir incrmenter une variable de boucle, mme si une itration particulire de la boucle a t interrompue par un next :
LIGNE: while (<STDIN>) { next LIGNE if /^#/; next LIGNE if /^$/; ... # ignore les commentaires # ignore les lignes blanches

customer_8566

Instructions de boucle
} continue { $compte++; }

107

Loprateur redo redmarre le bloc de boucle sans rvaluer la condition. Le bloc continue, sil existe, nest pas excut. Cet oprateur sutilise souvent pour des programmes qui veulent se cacher eux-mmes ce qui vient dtre entr. Supposons que vous traitez un fichier dont les lignes sont parfois termines par un antislash pour indiquer quelles continuent sur la ligne suivante. Voici un exemple dutilisation de redodans ce cas :
while (<>) { chomp; if (s/\\$//) { $_ .= <>; redo unless eof; # ne pas lire au-del de la fin de chaque fichier } # traitement de $_ }

qui est la version Perl usuelle du plus explicite (et laborieux) :


LIGNE: while (defined($ligne = <ARGV>)) { chomp($ligne); if ($ligne =~ s/\\$//) { $ligne .= <ARGV>; redo LIGNE unless eof(ARGV); } # traitement de $ligne }

Voici un exemple tir dun programme rel qui utilise les trois oprateurs de contrle de boucle. Bien que cette mthode soit moins courante maintenant que nous disposons des modules Getopt::* dans la distribution de Perl standard, cest toujours une illustration intressante de lutilisation des oprateurs de contrle de boucle sur des boucles nommes et imbriques :
ARG: while (@ARGV && $ARGV[0] =~ s/^-(?=.)//) { OPT: for (shift @ARGV) { m/^$/ && do { next m/^-$/ && do { last s/^d// && do { $Niveau_Debug++; redo s/^l// && do { $Genere_Listing++; redo s/^i(.*)// && do { $Sur_Place = $1 || ".bak"; next say_usage("Option inconnue : $_"); } }

ARG; ARG; OPT; OPT; ARG;

}; }; }; }; };

Encore un mot au sujet des oprateurs de contrle de boucle. Vous avez peut-tre remarqu que nous ne les appelons pas instructions . Ce ne sont en effet pas des instructions bien que comme toute expression, on puisse les utiliser comme des instructions. Vous pouvez presque les considrer comme des oprateurs unaires qui modifient le droulement du programme. En fait, vous pouvez mme vous en servir l o cela na aucun sens. On voit parfois cette erreur de codage :

customer_8566

108

Chapitre 4 Instructions et dclarations

open FICHIER, $fichier or warn "Impossible douvrir $fichier : $!\n", next FICHIER; # FAUX

Lintention est bonne, mais next FICHIER est analys comme lun des paramtres de warn, qui est un oprateur de liste. Donc le next sexcute avant que le warn ait la moindre chance dmettre son avertissement. Dans ce cas, cela se corrige facilement en changeant loprateur de liste warn en la fonction warn laide de parenthses bien places :
open FICHIER, $fichier or warn("Impossible douvrir $fichier : $!\n"), next FICHIER; # Correct

Nanmoins, vous trouverez peut-tre ceci plus facile lire :


unless (open FICHIER, $fichier) { warn "Impossible douvrir $fichier: $!\n"; next FICHIER; }

Blocs simples
Un BLOC (tiquet ou non) est en soi lquivalent smantique dune boucle qui sexcute une seule fois. Cest pourquoi vous pouvez utiliser last pour quitter un bloc ou redo pour relancer le bloc.5 Remarquez que ceci nest pas le cas des blocs lintrieur deval {}, de sub {} ou, ce qui en tonne beaucoup, de do {}. En effet, ce ne sont pas des blocs de boucle, car ce ne sont pas des blocs par eux-mmes. Le mot-cl qui les prcde fait deux les termes dexpressions qui se trouvent contenir un bloc de code. Ntant pas des blocs de boucle, ils ne peuvent tre tiquets et les contrles de boucle ne sy appliquent pas. Les contrles de boucle ne sappliquent quaux vritables boucles, tout comme return ne sutilise que dans un sous-programme (ou un eval). Les contrles de boucle ne marchent pas non plus avec un if ou un unless, puisque ce ne sont pas des boucles. Mais vous pouvez toujours ajouter une paire daccolades supplmentaires pour construire un bloc simple qui lui est une boucle :
if (/pattern/) {{ last if /alpha/; last if /beta/; last if /gamma/; # ne fait quelque chose que si on se trouve encore dans le if() }}

Voici comment utiliser un bloc pour faire fonctionner les oprateurs de contrle de boucle avec une construction do {}. Pour faire un next ou un redo sur un do, ajouter un bloc simple lintrieur :
do {{ next if $x == $y; # faire quelque chose ici }} until $x++ > $z;
5. Pour des raisons qui peuvent (ou non) paratre videntes la rf lexion, un next permet galement de sortir dun bloc. Il y a cependant une petite diffrence en ce quun next excute un bloc continue, ce qui nest pas le cas dun last.

customer_8566

Blocs simples
Vous devez tre plus subtil pour last :
{ do { last if $x = $y ** 2; # faire quelque chose ici } while $x++ <= $z; }

109

Et si vous voulez vous servir des deux contrles de boucle disponibles, vous allez devoir distinguer ces blocs avec des tiquettes :
DO_LAST: { do { DO_NEXT: { next DO_NEXT if $x == $y; last DO_LAST if $x = $y ** 2; # faire quelque chose ici } } while $x++ <= $z; }

Mais quand vous en arrivez ce point (ou mme avant), vous feriez mieux dutiliser une simple boucle infinie avec un last la fin :
for (;;) { next if $x == $y; last if $x = $y ** 2; # faire quelque chose ici last unless $x++ <= $z; }

Structures de cas
Contrairement dautres langages de programmation, Perl na pas dinstruction switch ou case officielle. Perl nen a pas besoin, puisquil y a plus dune manire de faire la mme chose. Un bloc simple est particulirement commode pour construire des structures choix multiples. En voici une :
SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $rien = 1; }

et une autre :
SWITCH: { /^abc/ /^def/ /^xyz/ $rien = 1; } && do { $abc = 1; last SWITCH; }; && do { $def = 1; last SWITCH; }; && do { $xyz = 1; last SWITCH; };

customer_8566

110

Chapitre 4 Instructions et dclarations

ou, format pour que chaque cas ressorte mieux :


SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; /^def/ }; && do { $def = 1; last SWITCH; /^xyz/ }; && do { $xyz = 1; last SWITCH; }; $rien = 1; }

ou mme, horreur :
if (/^abc/) { $abc = 1 } elsif (/^def/) { $def = 1 } elsif (/^xyz/) { $xyz = 1 } else { $rien = 1 }

Remarquez comme dans cet exemple loprateur last ignore les blocs do, qui ne sont pas des boucles, et sort de la boucle for :
for ($nom_de_variable_tres_long[$i++][$j++]->methode()) { /ce motif/ and do { push @flags, -e; last; }; /celui-l/ and do { push @flags, -h; last; }; /quelque chose dautre/ and do { last; }; die "valeur inconnue: `$_"; }

Vous pouvez trouver bizarre de boucler sur une seule valeur, puisque vous nallez traverser quune fois la boucle. mais il est commode de pouvoir utiliser les capacits dalias de for/foreach pour affecter $_ temporairement et localement. Cela rend les comparaisons multiples la mme valeur beaucoup plus faciles taper et il est donc plus difficile de se tromper. On chappe aux effets secondaires dune nouvelle valuation de lexpression. Et pour rester en rapport avec cette section, cest lun des idiomes les plus rpandus pour implmenter une structure de cas. Pour des cas simples, une cascade doprateurs ?: peut galement marcher. Ici encore, nous utilisons les capacits dalias de for afin de rendre les comparaisons multiples plus lisibles :
for ($couleur_utilisateur) { $value = /rouge/ ? 0xFF0000 : /vert/ ? 0x00FF00 : /bleu/ ? 0x0000FF : 0x000000 ; # noir sil ny a plus despoir }

Dans des situations comme celle-ci, il vaut parfois mieux vous construire un hachage et

customer_8566

goto

111

le classer rapidement pour en tirer la rponse. Contrairement aux conditions en cascade que nous avons vues, un hachage peut crotre un nombre illimit dlments sans prendre plus de temps pour trouver le premier ou le dernier lment. Linconvnient est que vous ne pourrez faire que des comparaisons exactes et pas des recherches de motif. Si vous avez un hachage comme celui-ci :
%couleur = ( azur chartreuse lavande magenta turquoise ); => => => => => 0xF0FFFF, 0x7FFF00, 0xE6E6FA, 0xFF00FF, 0x40E0D0,

alors une recherche exacte de chane tourne vite :


$valeur = $couleur{ lc $couleur_utilisateur } || 0x000000;

Mme les instructions compliques de branchement multiple (o chaque cas implique lexcution de plusieurs instructions diffrentes) peuvent se transformer en une rapide consultation. Vous avez juste besoin de vous servir dun hachage de rfrences des functions. Pour savoir comment les manipuler, voyez la section Hachages de fonctions au chapitre 9, Structures de donnes.

goto
Perl supporte aussi un oprateur goto, mais il nest pas destin aux curs sensibles. Il se prsente sous trois formes : goto LABEL, goto EXPR et goto &NOM. La forme goto LABEL trouve linstruction tiquete avec LABEL et reprend lexcution partir de l. Elle ne peut pas servir sauter lintrieur dune structure qui ncessite une initialisation, comme un sous-programme ou une boucle foreach. Elle ne peut pas non plus servir pour entrer dans une structure qui a t limine lors de loptimisation (voir le chapitre 18, Compilation). Elle peut servir pour aller peu prs nimporte o dans le bloc courant ou dans un bloc dans votre porte dynamique (cest--dire un bloc duquel vous avez t appel). Vous pouvez mme sortir dun sous-programme par goto, mais il vaut en gnral mieux utiliser une autre construction. Lauteur de Perl na jamais ressenti le besoin dutiliser cette forme de goto (en Perl ; en C, cest une autre affaire). La forme goto EXPR nest quune gnralisation de goto LABEL. Elle attend de lexpression quelle produise un nom dtiquette, dont la position doit videmment tre rsolue dynamiquement par linterprteur. Cela permet des goto calculs la FORTRAN, mais nest pas ncessairement recommand si vous cherchez optimiser la maintenabilit du code :
goto(("TOTO", "TITI", "TUTU")[$i]); @loop_label = qw/TOTO TITI TUTU/; goto $loop_label[rand @loop_label]; # en esprant que 0 <= i < 3

# tlportation au hasard

Dans presque tous les cas de ce genre, il est trs, trs largement prfrable dutiliser les mchanismes structurs de contrle de f lux de next, last ou redo au lieu davoir recours un goto. Pour certaines applications, un hachage de rfrences des fonctions

customer_8566

112

Chapitre 4 Instructions et dclarations

ou le mchanisme de capture et de gestion dexceptions sappuyant sur eval et die sont des approches prudentes. La forme goto &NAME est fortement magique et suffisamment loigne du gotousuel pour exempter ceux qui lutilisent de lopprobre qui couvre habituellement les utilisateurs de goto. Elle substitue la routine en cours dexcution un appel au sous-programme nomm. Ce fonctionnement est utilis par les routines AUTOLOAD pour charger un autre sous-programme et faire croire que cest cet autre sous-programme qui tait appel. Aprs le goto, mme caller ne pourra dire que cette routine a t appele en premier. Les modules autouse, AutoLoader et SelfLoader utilisent tous cette stratgie pour dfinir les fonctions lorsquelles sont appeles pour la premire fois puis les lancer sans que personne ne puisse jamais savoir que ces fonctions nont pas toujours t l.

Dclarations globales
Les dclarations de sous-programmes et de formats sont des dclarations globales. O que vous les placiez, ce quelles dclarent est global (cest local au paquetage, mais comme les paquetages sont globaux au programme, tout ce qui est dans un paquetage est visible de partout). Une dclaration globale peut tre place partout o lon peut mettre une instruction, mais na aucun effet sur lexcution de la squence primaire dinstructions, les dclarations prennent effet la compilation. Cela signifie que vous ne pouvez pas faire de dclaration conditionnelle de sous-programmes ou de formats et les cacher du compilateur au moyen dune condition qui ne sera prise en compte qu lexcution. Le compilateur voit les dclarations de sous-programmes et de formats (ainsi que les dclarations use et no) o quelles se produisent. Les dclarations globales sont gnralement mises au dbut ou la fin de votre programme, ou dans un autre fichier. Cependant si vous dclarez des variables porte lexicale (voir la section suivante), vous devrez vous assurer que vos dclarations de formats et de sous-programmes sont porte de vos dclarations de variables si vous esprez accder ces variables prives. Vous avez remarqu que nous sommes sournoisement passs des dclarations aux dfinitions. Sparer la dfinition de la dclaration a parfois un intrt. La seule diffrence syntaxique entre les deux est que la dfinition fournit un BLOC contenant le code excuter, et pas la dclaration. (Une dfinition de sous-programme agit comme une dclaration si aucune dclaration na t vue.) Sparer la dfinition de la dclaration vous permet de mettre la dclaration au dbut du fichier et la dfinition la fin (avec vos variables lexicales joyeusement au milieu) :
sub compte (@); # # my $x; # # $x = compte(3,2,1); # sub compte (@) { @_ } # Le compilateur compte(). Le compilateur lexicale. Le compilateur Le compilateur sait maintenant comment appeler connat maintenant la variable peut valider lappel de fonction. sait maintenant ce que fait compte().

Comme le montre cet exemple, les sous-programmes nont pas besoin dtre dfinis avant que les appels vers eux soient compils (en fait, leur dfinition peut mme tre repousse jusqu leur premire utilisation, si vous utilisez lautochargement), mais la

customer_8566

Dclarations globales

113

dclaration des sous-programmes aide le compilateur de diffrentes manires et vous donne plus de choix dans votre faon de les appeler. La dclaration dun sous-programme lui permet dtre utilis sans parenthses, comme sil sagissait dun oprateur intgr depuis ce point de la compilation. (Nous avons utilis des parenthses pour appeler compte dans lexemple prcdent, mais en fait nous nen avions pas besoin.) Vous pouvez dclarer un sous-programme sans le dfinir juste en disant :
sub monnom; $me = monnom $0 or die "Impossible de trouver mon nom";

Une dclaration simple comme celle-ci dclare la fonction comme un oprateur de liste et non comme un oprateur unaire, aussi faites attention utiliser or et non || dans ce cas. Loprateur || lie trop fortement pour tre utilis aprs des oprateurs de liste, mme si vous pouvez toujours mettre des parenthses autour des arguments de loprateur de liste pour le changer en appel de fonction. Autrement, vous pouvez utiliser le prototype ($) pour transformer la routine en oprateur unaire :
sub monnom ($); $me = monnom $0 || die "Impossible de trouver mon nom";

Cest maintenant analys comme vous vous y attendez, mais vous devriez tout de mme garder lhabitude dutiliser or dans cette situation. Pour en savoir plus sur les prototypes, voir le chapitre 6, Sous-programmes. Vous devez dfinir le sous-programme un moment donn, sinon vous obtiendrez une erreur lexcution indiquant que vous avez appel un sous-programme indfini. moins de dfinir le sous-programme vous-mme, vous pouvez rcuprer les dfinitions depuis dautres endroits de plusieurs faons. Vous pouvez charger les dfinitions depuis dautres fichiers avec une simple instruction require ; ctait la meilleure manire de charger des fichiers en Perl 4, mais elle pose deux problmes. Premirement, lautre fichier va typiquement insrer des noms de sous-programmes dans un paquetage (une table de symboles) de son choix, et non vos propres paquetages. Deuximement, un require se produit lexcution et donc arrive trop tard pour servir de dclaration dans le fichier invoquant le require. Il arrive cependant que vous cherchiez justement retarder le chargement. Une manire plus utile de charger les dclarations et les dfinitions est la dclaration use, qui fait un require du module la compilation (car use compte comme un bloc BEGIN) et vous laisse importer une partie des dclarations du module dans votre propre programme. On peut donc considrer use comme une dclaration globale en ce quelle importe les noms la compilation dans votre propre paquetage (global) comme si vous les aviez dclars vous-mme. Voir la section Tables de symboles, au chapitre 10, Paquetages au sujet du fonctionnement bas niveau de limportation entre paquetages, le chapitre 11, Modules, pour savoir comment configurer les paramtres dimportation et dexportation des modules, et le chapitre 18 pour une explication de BEGIN et de ses cousins CHECK, INIT et END, qui sont aussi des sortes de dclarations globales puisquelles sont traites la compilation et peuvent avoir un effet global.

customer_8566

114

Chapitre 4 Instructions et dclarations

Dclarations avec porte


Comme les dclarations globales, les dclarations porte lexicale ont un effet au moment de la compilation. Contrairement aux dclarations globales, les dclarations porte lexicale ne sappliquent que du point de dclaration jusqu la fin du bloc encadrant le plus interne (le premier bloc, fichier ou eval trouv). Cest pourquoi nous les appelons porte lexicale, bien que le terme porte textuelle soit peut-tre plus exact, puisque la porte lexicale na rien voir avec les lexiques. Mais les informaticiens du monde entier savent ce que signifie porte lexicale , aussi perptuons-nous cet usage ici. Perl supporte aussi les dclarations porte dynamique. Une porte dynamique stend aussi jusqu la fin du bloc encadrant le plus interne, mais encadrant dans ce cas est dfini dynamiquement lexcution, plutt que textuellement la compilation. Pour le dire autrement, les bloc sembotent dynamiquement en invoquant dautres blocs, pas en les incluant. Cet embotement de portes dynamiques peut tre corrl en quelque sorte lembotement des portes lexicales, mais les deux sont en gnral diffrents, particulirement quand des sous-programmes ont t invoqus. Nous avons mentionn que certains aspects de use pouvaient tre considrs comme des dclarations globales, mais dautres aspects de use sont porte lexicale. En particulier, use nimporte pas seulement les symboles, mais implmente galement diverses directives de compilation magiques, connues sous le nom de pragmas (ou si vous prfrez la forme classique, pragmata). La plupart des pragmas sont porte lexicale, y compris le pragma use strict vars qui vous oblige dclarer vos variables avant de vous en servir. Voir plus loin la section Pragmas. Une dclaration package, curieusement, est elle-mme porte lexicale, malgr le fait quun paquetage est une entit globale. Mais une dclaration package se contente de dclarer lidentit du paquetage par dfaut pour le reste du bloc lencadrant. Les noms de variables non dclars, non qualifis6 sont recherchs dans ce paquetage. En un sens, un paquetage nest jamais dclar du tout, mais il se met exister quand vous faites rfrence quelque chose qui appartient ce paquetage. Cest trs Perlien.

Dclarations de variables porte limite


Le reste de ce chapitre parle surtout de lutilisation de variables globales. Ou plutt, parle de la non utilisation de variables globales. Il existe plusieurs dclarations qui vous aident ne pas utiliser de variables globales ou au moins ne pas les utiliser btement. Nous avons dj mentionn la dclaration package, qui a t introduite en Perl il y a bien longtemps pour pouvoir sparer les variables globales en paquetages spars. Cela marche assez bien pour un certain type de variables. Les paquetages sont utiliss par des bibliothques, des modules et des classes pour stocker leurs donnes dinterface (et certaines de leur donnes semi-prives) pour viter les conf lits avec des variables et des

6. Et aussi les noms de sous-programmes, handles de fichiers, handles de rpertoires et formats non qualifis.

customer_8566

Dclarations avec porte

115

fonctions de mme nom dans votre programme principal ou dans dautres modules. Si vous voyez quelquun cire $Quelque::chose,7 il se sert de la variable scalaire $chose du paquetage Quelque. Voir le chapitre 10. Si ctait tout ce quil existait en la matire, les programmes Perl deviendraient de plus en plus difficiles manipuler en grossissant. Heureusement, les trois dclarations de porte de Perl permettent de crer facilement des variables compltement prives (avec my), de donner slectivement laccs aux globales (avec our) et de donner des valeurs temporaires des variables globales (avec local).
my $nose; our $House; local $TV_channel;

Si plusieurs variables sont listes, la liste doit tre place entre parenthses. Pour my et our, les lments ne peuvent tre que de simples scalaires, tableaux ou hachages. Pour local, les contraintes sont quelque peu relches : vous pouvez galement localiser des typeglobs en entier ou de simples lments, ou des tranches de tableaux ou de hachages :
my ($nose, @eyes, %teeth); our ($House, @Autos, %Kids); local (*Spouse, $phone{HOME});

Chacun de ces modificateurs propose une sorte disolation diffrente aux variables quil modifie. Pour simplifier lgrement : our confine les noms une porte, local confine les valeurs une porte, et my confine la fois les noms et les valeurs une porte. Ces constructions peuvent se voir affecter des valeurs, mais diffrent en ce quelles font rellement avec ces valeurs, puisquelles proposent des mcanismes diffrents de stockage des valeurs. Elles sont aussi quelque peu diffrentes quand vous ne leur affectez aucune valeur (comme dans notre exemple ci-dessus) : my et local font dmarrer les variables en question la valeur undef ou () approprie selon le contexte ; our au contraire ne modifie pas la valeur de la variable globale associe. Syntaxiquement, my, our et local sont simplement des modificateurs (comme des adjectifs) agissant sur une lvalue. Quand vous affectez une lvalue modifie, le modificateur ne change pas le fait que la lvalue soit vue comme un scalaire ou une liste. Pour savoir comment le modificateur va fonctionner, faites comme sil ntait pas l. Ces deux constructions fournissent donc un contexte de liste du ct droit :
my ($toto) = <STDIN>; my @tableau = <STDIN>;

Tandis que celle-ci fournit un contexte scalaire :


my $toto = <STDIN>;

Les modificateurs lient plus fort (avec une prcdence suprieure) que loprateur virgule. Lexemple suivant ne dclare quune variable au lieu de deux, car la liste qui suit le modificateur nest pas entre parenthses.

7. Ou larchaque $Quelquechose qui ne devrait probablement pas tre encourag en dehors de la posie Perl.

customer_8566

116
my $toto, $titi = 1;

Chapitre 4 Instructions et dclarations


# FAUX

Cela a le mme effet que :


my $toto; $titi = 1;

Vous serez averti de cette erreur si vous avez demand les avertissements, avec les options de ligne de commande -w ou -W, ou de prfrence avec la dclaration use warnings explique plus loin dans la section Pragmas. En gnral, il vaut mieux dclarer une variable dans la plus petite porte ncessaire. Comme les variables dclares dans des instructions de contrle de f lux ne sont visibles que dans le bloc concern par cette instruction, leur visibilit est rduite. Cela se lit galement mieux en anglais (ce qui a moins dintrt pour ceux qui codent en franais).
sub verifie_stock { for my $machin (our @Inventaire) { print "Jai un $machin en stock aujourdhui.\n"; } }

La forme de dclaration la plus frquente est my, qui dclare des variables porte lexicale dont le nom et la valeur sont stocks dans le bloc-note temporaire de la porte en cours et ne peuvent tre accds de manire globale. La dclaration our est trs proche de cela, et fait entrer un nom lexical dans la porte en cours, tout comme my, mais pointe en ralit vers une variable globale laquelle nimporte qui pourrait accder sil le voulait. En dautres termes, cest une variable globale maquille en variable lexicale. Lautre forme de porte, la porte dynamique, sapplique aux variables dclares avec local, qui malgr lemploi du mot local sont en fait des variables globales qui nont rien voir avec le bloc-notes local.

Variables porte lexicale : my


Pour vous viter le casse-tte du suivi des variables globales, Perl fournit des variables porte lexicale, appeles parfois lexicales pour faire court. Contrairement aux globales, les lexicales vous garantissent le secret de vos variables. Tant que vous ne distribuez pas des rfrences ces variables prives qui permettraient de les tripatouiller indirectement, vous pouvez tre sr que tous les accs possibles ces variables prives sont restreints au code contenu dans une section limite et aisment identifiable de de votre programme. Aprs tout, cest la raison pour laquelle nous avons choisi le mot-cl my. Une squence dinstructions peut contenir des dclarations de variables porte lexicale. De telles dclarations sont habituellement places au dbut de la squence dinstructions, mais ce nest pas une obligation. En plus de dclarer les noms de variables la compilation, les dclarations fonctionnent comme des instructions normales lexcution : chacune dentre elles est labore dans la squence dinstructions comme sil sagissait dune instruction usuelle sans le modificateur :
my $nom = "fred"; my @affaires = ("voiture", "maison", "marteau"); my ($vehicule, $domicile, $outil) = @affaires;

Ces variables lexicales sont totalement caches du monde lextrieur de la porte les

customer_8566

Dclarations avec porte

117

contenant immdiatement. Contrairement aux effets de porte dynamique de local (voir la section suivante), les lexicales sont caches tout sous-programme appel depuis leur porte. Cela reste vrai mme si le mme sous-programme est appel depuis luimme ou ailleurs chaque instance du sous-programme possde son propre blocnotes de variables lexicales. Contrairement aux portes de blocs, les portes de fichiers ne sembotent pas ; il ne se produit pas d inclusion , tout au moins pas textuellement. Si vous chargez du code dun autre fichier avec do, require ou use, le code contenu dans ce fichier ne pourra pas accder vos variables lexicales, tout comme vous ne pourrez pas accder aux siennes. Cependant toute porte lintrieur dun fichier (ou mme le fichier lui-mme) fait laffaire. Il est souvent utile davoir des portes plus larges que la dfinition de sous-programme, car cela vous permet de de partager des variables prives avec un nombre limit de routines. Cest ainsi que vous crez des variables quun programmeur C appellerait statiques :
{ my $etat = 0; sub on { $etat = 1 } sub off { $etat = 0 } sub change { $etat = !$etat } }

Loprateur eval CHAINE fonctionne aussi comme une porte embote, puisque le code lintrieur de leval peut voir les variables lexicales de lappelant (tant que leurs noms ne sont pas cachs par des dclarations identiques dans la porte dfinie par leval luimme). Les routines anonymes peuvent de mme accder nimporte quelle variable lexicale des portes les renfermant ; si elles le font, elles sont alors nommes fermetures.8 En combinant ces deux notions, si un bloc evalue une chane qui cre un sous-programme anonyme, ce sous-programme devient une fermeture avec accs complet aux lexicales de levalet du bloc, mme aprs que le leval et le bloc se sont termins. Voir la section Fermetures au chapitre 8. La variable nouvellement dclare (ou la valeur, dans le cas de local) napparat pas avant la fin de linstruction suivant linstruction contenant la dclaration. Vous pourriez donc copier une variable de cette faon :
my $x = $x;

Cela initialise le nouveau $x interne avec la valeur courante de $x, que la signification de $x soit globale ou lexicale. (Si vous ninitialisez pas la nouvelle variable, elle dmarre avec une valeur vide ou indfinie.) La dclaration dune variable lexicale dun nom donn cache toute variable lexicale du mme nom dclare prcdemment. Elle cache aussi toute variable globale non qualifie du mme nom, mais celle-ci reste toujours accessible en la qualifiant explicitement avec le nom du paquetage la contenant, par exemple $NomPaquetage::nomvar.

8. La vritable dfinition de la fermeture vient dune notion mathmatique concernant la compltude densembles de valeurs et des oprateurs sur ces valeurs.

customer_8566

118

Chapitre 4 Instructions et dclarations

Dclarations de globales porte lexicale : our


La dclaration our est une meilleure manire daccder aux globales, en particulier pour les programmes et les modules tournant avec la dclaration use strict. Cette dclaration est porte lexicale dans le sens o elle ne sapplique que jusqu la fin de la porte courante. Mais contrairement au my porte lexicale ou au local porte dynamique, our nisole rien dans la porte lexicale ou dynamique en cours. En fait, il donne accs une variable globale dans le paquetage en cours, en cachant les lexicales de mme nom qui vous auraient sinon empch de voir cette globale. cet gard, nos variables our fonctionnent tout comme mes variables my. Si vous placez une dclaration our en dehors de tout bloc dlimit par des accolades, elle dure jusqu la fin de lunit de compilation en cours. Souvent, on la place juste au dbut de la dfinition dun sous-programme pour indiquer quil accde une variable globale :
sub verifie_entrepot { our @Inventaire_Courant; my $machin; foreach $machin (@Inventaire_Courant) { print "Jai un $machin en stock aujourdhui.\n"; } }

Comme les variables globales ont une dure de vie plus longue et une visibilit plus large que les variables prives, nous prfrons utiliser pour elles des noms plus longs et plus voyants que pour les variables temporaires. Cette simple habitude, si elle est suivie consciencieusement, peut faire autant que use strict pour dcourager lemploi de variables globales, particulirement chez ceux qui ne sont pas des virtuoses du clavier. Des dclarations our rptes ne sembotent pas clairement. Chaque my embot produit une nouvelle variable, et chaque local embot produit une nouvelle valeur. Mais chaque fois que vous employez our, vous mentionnez la mme variable globale, sans notion dembotement. Quand vous affectez une variable our, les effets de cette affectation persistent une fois hors de porte de la dclaration. Cest parce que our ne cre jamais de valeur ; il donne seulement une forme daccs limit la globale qui, elle, existe pour toujours :
our $NOM_PROGRAMME = "client"; { our $NOM_PROGRAMME = "serveur"; # Le code appel dici voit "serveur". ... } # Le code excut ici voit toujours "serveur".

Comparez ceci avec ce qui arrive avec my ou local, quand la variable ou la valeur redevient visible aprs le bloc :
my $i = 10; { my $i = 99; ... }

customer_8566

Dclarations avec porte


# Le code compil ici voit la variable externe. local $NOM_PROGRAMME = "client"; { local $NOM_PROGRAMME = "serveur"; # Le code appel dici voit "serveur". ... } # Le code excut ici voit "client" de nouveau.

119

Faire une dclaration our na en gnral de sens quune seule fois, probablement tout au dbut de votre programme ou module ou, plus rarement, quand vous prfixez le our de son propre local :
{ local our @Inventaire_Courant = qw(bananes); verifie_entrepot(); # non, nous navons pas de bananes :-) }

Variables porte dynamique : local


Lutilisation de loprateur local sur une variable globale lui donne une valeur temporaire chaque fois que local est excut, mais naffecte pas la visibilit globale de cette variable. Quand le programme atteint la fin de cette porte dynamique, cette valeur temporaire est jete et la valeur prcdente restaure. Mais pendant que ce bloc sexcute, cest toujours une variable globale qui se trouve juste contenir une valeur temporaire. Si vous appelez une autre fonction pendant que votre variable globale contient la valeur temporaire et que cette fonction accde cette variable globale, elle verra la valeur temporaire et pas la valeur initiale. En dautres termes, cette autre fonction est dans votre porte dynamique, mme si elle nest probablement pas dans votre porte lexicale.9 Si vous avez un local qui ressemble ceci :
{ local $var = $nouveau; ma_fonction(); ... }

vous pouvez le voir entirement en termes daffectations lexcution :


{ $ancien = $var; local $var = $nouveau; ma_fonction(); ... }

9. Cest pourquoi on appelle parfois la porte lexicale une porte statique : pour contraster avec la porte dynamique et insister sur le fait quelle est dtermine la compilation. Ne confondez pas cette utilisation avec lemploi du mot-cl static en C ou en C++. Le terme est trs charg, cest pourquoi nous lvitons.

customer_8566

120
continue { $var = $ancien; }

Chapitre 4 Instructions et dclarations

La diffrence est quavec local, la valeur est restaure quelle que soit la manire dont vous quittez le bloc, mme si vous sortez de cette porte en faisant un returnprmatur. La variable est toujours la mme variable globale, mais la valeur qui sy trouve dpend de la porte do la fonction a t appele. Cest pourquoi on lappelle porte dynamique : parce quelle change au cours de lexcution. Comme avec my, vous pouvez initialiser un local avec une copie de la mme variable globale. Toutes les modifications faites cette variable pendant lexcution du sous-programme (et de tous les autres appels depuis celui-ci, qui peuvent bien sr voir cette globale porte dynamique) seront perdues quand la routine se terminera. Vous devriez srement commenter ce que vous faites :
# ATTENTION : les modifications sont temporaires # pour cette porte dynamique local $Ma_Globale = $Ma_Globale;

Une variable globale est donc toujours visible dans lintgralit de votre programme, quelle ait t dclare avec our, quelle ait t cre la vole ou quelle contienne une valeur locale destine tre jete une fois hors de porte. Ce nest pas compliqu pour de petits programmes. Mais vous allez rapidement ne plus retrouver o sont utilises ces variables globales dans de plus gros programmes. Si vous voulez, vous pouvez interdire lutilisation accidentelle de variables globales laide du pragma use strict vars, dcrit la section suivante. Bien que my et local confrent toutes deux un certain niveau de protection, vous devriez largement prfrer my local. Cependant, vous devrez de temps en temps utiliser localpour pouvoir modifier temporairement la valeur dune variable globale existante, comme celles dcrites au chapitre 28, Noms spciaux. Seuls les identificateurs alphanumriques peuvent avoir une porte lexicale et beaucoup de ces variables spciales ne sont pas strictement alphanumriques. Vous aurez aussi besoin de local pour faire des modifications temporaires la table des symboles dun paquetage, comme cest dcrit dans la section Tables de symboles au chapitre 10. Enfin, vous pouvez aussi utiliser local sur un lment isol ou tout une tranche dun tableau ou dun hachage. Cela fonctionne mme si le tableau ou le hachage est en fait une variable lexicale, en rajoutant la couche de comportement de porte dynamique de local au dessus de ces variables lexicales. Nous ne parlerons pas plus de la smantique de local ici. Pour plus dinformations, voir local au chapitre 29.

Pragmas
De nombreux langages de programmation vous permettent de donner des directives au compilateur. En Perl ces directives sont passes au compilateur par la dclaration use. Certains de ces pragmas sont :
use use use use use warnings; strict; integer; bytes; constant pi => ( 4 * atan2(1,1) );

customer_8566

Pragmas

121

Les pragmas de Perl sont dcrits au chapitre 31, Modules de pragmas, mais nous allons tout de suite parler des plus utiles par rapport au contenu de ce chapitre. Bien que certains soient des dclarations qui affectent les variables globales ou le paquetage en cours, la plupart des pragmas sont des dclarations porte lexicale dont les effets ne durent que jusqu la fin du bloc, du fichier ou de leval qui les contient (en fonction du premier qui se prsente). Un pragma porte lexicale peut tre annul dans une porte incluse avec une dclaration no, qui fonctionne exactement comme use, mais lenvers.

Contrle des avertissements


Pour vous montrer comment tout cela fonctionne, nous allons manipuler le pragma warnings pour dire Perl sil doit nous avertir de pratiques discutables :
use warnings; # Permet les avertissements dici la fin de fichier ... { no warnings; # Dsactive les avertissements dans le bloc ... } # Les avertissements sont automatiquement ractivs ici

Une fois les avertissements demands, Perl vous signalera les variables utilises une seule fois, les dclarations qui cachent dautres dclarations dans la mme porte, les conversions incorrectes de chanes en nombres, lutilisation de valeurs indfinies comme des nombres ou des chanes normaux, les tentatives dcriture sur des fichiers ouverts en lecture seule (ou pas ouverts du tout) et bien dautres problmes potentiels lists au chapitre 33, Messages de diagnostic. La mthode de contrle des avertissements recommande est lutilisation de use warnings. Les anciens programmes ne pouvaient utiliser que loption de ligne de commande -w ou bien modifier la variable globale $^W :
{ local $^W = 0; ... }

Il vaut beaucoup mieux utiliser les pragmas use warnings et no warnings. Un pragma vaut mieux car il se produit la compilation, parce que cest une dclaration lexicale et ne peut donc pas affecter du code quil ntait pas cens affecter, et (bien que nous ne vous layons pas montr dans ces simples exemples) quil permet un contrle plus fin sur plusieurs ensembles de classes. Pour en savoir plus sur le pragma warnings, y compris comment transformer des avertissements qui font juste un peu de bruit en erreurs fatales et comment supplanter le pragma pour activer les avertissements mme si le module ne veut pas, voir use warnings au chapitre 31.

Contrle de lutilisation des globales


Une autre dclaration communment rencontre est le pragma use strict, qui a plusieurs fonctions dont celle de contrler lutilisation des variables globales. Normalement, Perl vous laisse crer de nouvelles variables (ou trop souvent, craser danciennes

customer_8566

122

Chapitre 4 Instructions et dclarations

variables) simplement en les citant. Aucune dclaration de variable nest ncessaire (par dfaut). Sachant que lutilisation dbride de globales peut rendre les gros programmes ou les gros modules pnibles maintenir, vous pourrez vouloir dcourager leur utilisation accidentelle. Pour prvenir de tels accidents, vous pouvez crire :
use strict vars;

Cela signifie que toute variable mentionne partir dici jusqu la fin de la porte courante doit faire rfrence soit une variable lexicale, soit une variable globale explicitement autorise. Si ce nest pas le cas, une erreur de compilation se produit. Une variable globale est explicitement autorise si lune de ces propositions est vraie : Cest lune des variables spciales de Perl (voir le chapitre 28). Elle est compltement dfinie avec son nom de paquetage (voir le chapitre 10). Elle a t importe dans le paquetage courant (voir le chapitre 11). Elle se fait passer pour une variable lexicale laide dune dclaration our. (Cest la raison principale pour laquelle nous avons ajout la dclaration our Perl.)

Bien sr, il reste toujours la cinquime possibilit. Si le pragma est trop exigeant, annulez-le simplement dans un bloc intreur avec :
no strict vars

Avec ce pragma vous pouvez aussi demander une vrification stricte des drfrencements symboliques et de lutilisation des mot simples. Habituellement, les gens tapent juste :
use strict;

pour mettre en uvre les trois restrictions. Pour plus dinformations, voir lentre use strict, au chapitre 31.

customer_8566

Recherche de motif

Le support intgr de Perl pour la recherche de motif vous permet de rechercher dans de grandes quantits de donnes simplement et efficacement. Que vous fassiez tourner un norme site portail commercial balayant tous les groupes de news existants la recherche de potins intressants, un organisme public occup comprendre la dmographie humaine (ou le gnome humain), une institution scolaire dsireuse de mettre des informations dynamiques sur votre site web, Perl est loutil quil vous faut ; dune part cause de ses liens avec les bases de donnes, mais surtout cause de ses capacits de recherche de motif. Si vous prenez le mot texte dans son sens le plus large, prs de 90% de tout ce vous faites est du traitement de texte. Cest vraiment ce pour quoi Perl est fait et a toujours t fait en fait, cela fait mme partie de son nom : Practical Extraction and Report Language. Les motifs de Perl fournissent de puissants moyens pour ratisser des montagnes de donnes brutes et en extraire de linformation utile. Vous spcifiez un motif en crant une expression rationnelle (ou expression rgulire1 ou regex) et le moteur dexpressions rgulires de Perl (le Moteur , pour le reste de ce chapitre) prend cette expression et dtermine si (et comment) le motif correspond vos donnes. Alors que la plupart de vos donnes seront probablement des chanes de caractres, rien ne vous empche de vous servir des regex pour rechercher et remplacer nimporte quelle squence de bits, y compris ce que vous auriez cru tre des donnes binaires . Pour Perl, les octets sont juste des caractres qui ont une valeur ordinale infrieure 256. (Pour en savoir plus sur ce sujet, voir le chapitre 15, Unicode.) Si vous connaissiez dj les expressions rgulires avec dautres outils, nous devons vous prvenir que celles de Perl sont un peu diffrentes. Premirement elles ne sont pas vraiment rgulires (ou rationnelles ) au sens thorique du mot, ce qui signifie quelles peuvent faire beaucoup plus que les expressions rationnelles quon apprend en

1. NdT : Regular expression a deux traductions en franais : expression rationnelle , qui est un terme plutt acadmique, et expression rgulire , qui ressemble fort au terme utilis par les anglophones. Dans ce livre nous utiliserons plutt le second (et son abrviation anglaise regex ), mais il est possible quun peu de rationalit se glisse ici ou l...

customer_8566

124

Chapitre 5 Recherche de motif

cours dinformatique. Deuximement, elles sont tellement utilises en Perl, quelles ont leurs propres variables spciales et leur propres conventions de citation qui sont troitement intgres au langage, pas vaguement lies comme nimporte quelle autre librairie. Les nouveaux programmeurs Perl cherchent souvent en vain des fonctions comme :
match( $chaine, $motif ); subst( $chaine, $motif, $remplacement );

Mais la recherche et la substitution sont deux tches si fondamentales en Perl quelle mritent leurs propres oprateurs dune lettre : m/MOTIF/ et s/MOTIF/REMPLACEMENT/. Ils sont non seulement brefs syntaxiquement, mais ils sont aussi analyss comme des chanes entre apostrophes doubles plutt que comme des oprateurs ordinaires ; toutefois, ils fonctionnent comme des oprateurs, cest pourquoi nous les appelons ainsi. Tout au long de ce chapitre, vous les verrez utiliss pour comparer des motifs des chanes. Si une partie de la chane correspond au motif, nous disons que la correspondance (ou recherche) est russie. Il y a plein de trucs sympas faire avec des correspondances russies. En particulier, si vous utilisez s///, une correspondance russie provoque le remplacement de la partie correspondante dans la chane parce que vous avez spcifi comme REMPLACEMENT. Tout ce chapitre concerne la construction et lutilisation de motifs. Les expressions rgulires de Perl sont puissantes, et concentrent beaucoup de sens en peu de volume. Elles peuvent donc vous intimider si vous essayez de saisir le sens dun long motif dun seul coup. Mais si vous pouvez le dcouper en petits morceaux et que vous savez comment le Moteur interprte ces morceaux, vous pouvez comprendre nimporte quelle expression rgulire. Il nest pas rare de voir une centaine de lignes de code C ou Java exprimes en une expression rgulire dune ligne en Perl. Cette expression rgulire est peut-tre un peu plus difficile comprendre que nimporte quelle ligne du gros programme ; dun autre ct, la regex sera beaucoup plus facile comprendre que le plus long programme pris dans son ensemble. Il vous faut juste garder tout cela en perspective.

Bestiaire des expressions rgulires


Avant de nous plonger dans les rgles dinterprtation des expressions rgulires, regardons quoi certains motifs ressemblent. La plupart des caractres dune expression rgulire se correspondent eux-mmes. Si vous enchanez plusieurs caractres la suite, ils se correspondent dans lordre, comme on sy attend. Donc si vous crivez la recherche suivante :
/Frodon/

vous pouvez tre sr que le motif ne correspondra que si la chane contient quelque part la sous-chane Frodon . (Une sous-chane est juste un morceau de chane.) La correspondance peut se faire nimporte o dans la chane, tant que ces six caractres apparaissent quelque part, lun aprs lautre et dans cet ordre. Dautres caractres ne se correspondent pas eux-mmes, mais se comportent dune trange manire. Nous les appelons mtacaractres. (Tous les mtacaractres sont des coquins, mais certains sont si mauvais, quils conduisent les caractres voisins se comporter aussi mal queux.)

customer_8566

Bestiaire des expressions rgulires


Voici les sclrats :
\ | ( ) [ { ^ $ * + ? .

125

Les mtacaractres sont en fait trs utiles et ont une signification spciale lintrieur des motifs. Nous vous expliquerons toutes ces significations au fur et mesure de ce chapitre. Mais sachez dabord que vous pourrez toujours dtecter nimporte lequel de ces douze caractres en le faisant prcder dun antislash. Par exemple, comme lantislash est un mtacaractre, pour dtecter un antislash, vous devrez lantislasher : \\. Vous voyez, lantislash est le genre de caractre qui pousse les autres caractres mal se conduire. Finalement, quand vous faites mal se conduire un mtacaractre indisciplin, il se conduit bien un peu comme une double ngation. Antislasher un caractre pour le prendre littralement marche, mais seulement sur les caractres de ponctuation ; antislasher un caractre alphanumrique (qui habituellement se comporte correctement) fait le contraire : cela transforme le caractre littral en quelque chose de spcial. Ds que vous voyez une telle squence de deux caractres :
\b \D \t \3 \s

vous saurez que la squence est un mtasymbole qui correspond quelque chose dtrange. Par exemple, \b correspond une limite de mot, tandis que \t correspond un caractre de tabulation ordinaire. Remarquez quune tabulation fait un caractre de large, alors que la limite de mot a une largeur de zro caractre, puisque cest un point entre deux caractres. Nous appellerons donc \b une assertion de largeur nulle. Cependant, \t et \b se ressemblent en ce quils supposent quelque chose sur une caractristique de la chane. chaque fois que vous faites une assertion au sujet de quelque chose dans une expression rgulire, vous demandez ce que quelque chose en particulier soit vrai pour que le motif corresponde. La plupart des lments dune expression rgulire sont des assertions, y compris les caractres ordinaires qui veulent se correspondre eux-mmes. Pour tre plus prcis, ils supposent aussi que le prochain lment sera en correspondance un caractre plus loin dans la chane, cest pourquoi nous disons que la tabulation est de largeur un caractre . Certaines assertions (comme \t) consomment un peu de la chane au fur et mesure quils entrent en correspondance et dautres (comme \b) non. Mais nous rservons en gnral le terme assertion pour les assertions de largeur nulle. Pour viter les confusions, nous appellerons celles qui ont une largeur des atomes. (Si vous tes physicien, vous pouvez voir les atomes de largeur non nulle comme des particules massives, la diffrence des assertions, qui nont pas de masse comme les photons.) Vous allez voir aussi des mtacaractres qui ne sont pas des assertions ; ils sont plutt structurels (tout comme les accolades et les points-virgules dfinissent la structure du code Perl, mais ne font pas vraiment quelque chose). Ces mtacaractres structurels sont dune certaine manire les plus importants, car le premier pas dans votre apprentissage de la lecture des expressions rgulires est dhabituer votre regard reconnatre les mtacaractres structurels. Une fois que vous avez appris cela, lire des expressions rgulires est un jeu denfant2.

2. Denfant prcoce parfois, mais pas besoin dtre un futur Prix Nobel.

customer_8566

126

Chapitre 5 Recherche de motif

Lun de ces mtacaractres structurels est la barre verticale, qui indique un choix :
/Frodon|Pippin|Merry|Sam/

Cela signifie que nimporte laquelle de ces chanes peut correspondre. Ceci est trait dans la section Alternative plus loin dans ce chapitre. Dans la partie Capture et regroupement, nous vous montrerons comment utiliser les parenthses autour de morceaux de votre motif pour faire des regroupements :
/(Frodon|Drogon|Bilbon) Sacquet/

ou mme :
/(Frod|Drog|Bilb)on Sacquet/

Une autre chose que vous verrez sont les quantificateurs, qui disent combien de fois ce qui prcde doit tre trouv la queue-leu-leu. Les quantificateurs ressemblent ceci :
* + ? *? {3} {2,5}

Vous ne les verrez cependant jamais isolment. Les quantificateurs nont de sens quattachs des atomes cest--dire des assertions qui ont une largeur non nulle.3 Les quantificateurs sattachent latome prcdent seulement. Ce qui signifie en termes clairs quils ne quantifient normalement quun seul caractre. Si vous voulez une correspondance avec trois copies de bar la suite, vous devez regrouper les caractres individuels de bar dans une seule molcule avec des parenthses, comme ceci :
/(bar){3}/

Cela correspondra avec barbarbar . Si vous aviez crit /bar{3}/, cela aurait correspondu avec barrr qui aurait sonn cossais mais naurait pas constitu un barbarbarisme. Pour en savoir plus sur les quantificateurs, voir plus loin la section Quantificateurs. Maintenant que vous avez rencontr quelques-unes des bestioles qui habitent les expressions rgulires, vous tes srement impatient de commencer les apprivoiser. Cependant, avant que nous ne discutions srieusement des expressions rgulires, nous allons un petit peu rebrousser chemin et parler des oprateurs qui utilisent les expressions rgulires. (Et si vous apercevez quelques nouvelles bestioles regex en chemin, noubliez pas le guide.)

Oprateurs de recherche de motifs


Zoologiquement parlant, les oprateurs de recherche de motif de Perl fonctionnent comme une sorte de cage expressions rgulires : ils les empchent de sortir. Si nous laissions les regex errer en libert dans le langage, Perl serait une jungle complte. Le monde a besoin de jungles bien sr aprs tout, ce sont les moteurs de la diversit biologique mais les jungles devraient rester o elles sont. De mme, bien qutant le

3. Les quantificateurs sont un peu comme les modificateurs dinstructions du chapitre 4, Instructions et dclarations, qui ne peuvent sattacher qu une instruction simple. Attacher un quantificateur une assertion de largeur nulle, cela reviendrait essayer dattacher un modificateur while une dclaration ces deux actions tant aussi senses que de demander un chimiste une livre de photons. Les chimistes ne travaillent quavec des atomes.

customer_8566

Oprateurs de recherche de motifs

127

moteur de la diversit combinatoire, les expressions rgulires devraient rester lintrieur des oprateurs de recherche de motifs o est leur place. Cest une jungle, l-dedans. Comme si les expressions rgulires ntaient pas assez puissantes, les oprateurs m// et s/// leur donnent le pouvoir (lui aussi confin) de linterpolation entre apostrophes doubles. Comme les motifs sont analyss comme des chanes entre apostrophes doubles, toutes les conventions usuelles des apostrophes doubles fonctionnent, y compris linterpolation de variables ( moins que vous nutilisiez les apostrophes simples comme dlimiteurs) et les caractres spciaux indiqus par des squences dchappement avec antislash. (Voir Caractres spcifiques plus loin dans ce chapitre.) Celles-ci sont appliques avant que la chane soit interprte comme une expression rgulire. (Cest lun des quelques endroits de Perl o une chane subit un traitement en plusieurs passes.) La premire passe nest pas une interprtation entre apostrophes doubles tout fait normale, en ce quelle sait ce quelle doit interpoler et ce quelle doit passer lanalyseur dexpressions rgulires. Donc par exemple, tout $ immdiatement suivi dune barre verticale, dune parenthse fermante ou de la fin de chane ne sera pas trait comme une interpolation de variable, mais comme la traditionnelle assertion de regex qui signifie fin-de-ligne. Donc si vous crivez :
$toto = "titi"; /$toto$/;

la passe dinterpolation entre apostrophes doubles sait que ces deux $ fonctionnent diffremment. Elle fait linterpolation de $toto puis envoie ceci lanalyseur dexpressions rgulires :
/titi$/;

Une autre consquence de cette analyse en deux passes est que le tokener ordinaire de Perl trouve la fin de lexpression rgulire en premier, tout comme sil cherchait le dlimiteur final dune chane ordinaire. Cest seulement aprs avoir trouv la fin de la chane (et fait les interpolations de variables) que le motif est trait comme une expression rgulire. Entre autres choses, cela signifie que vous ne pouvez pas cacher le dlimiteur final dun motif lintrieur dun lment de regex (comme une classe de caractres ou un commentaire de regex, que nous navons pas encore couvert). Perl verra le dlimiteur o quil se trouve et terminera le motif cet endroit. Vous devez galement savoir que linterpolation de variables dans un motif ralentit lanalyseur de motif, car il se sent oblig de vrifier si la variable a t modifie, au cas o il aurait recompiler le motif (ce qui le ralentira encore plus). Voir la section Interpolation de variables plus loin dans ce chapitre. Loprateur de translittration tr/// ne fait pas dinterpolation de variables ; il nutilise mme pas dexpressions rgulires ! (En fait, il ne devrait probablement pas faire partie de ce chapitre, mais nous navons pas trouv de meilleur endroit o le mettre.) Il a cependant une caractristique commune avec m// et s/// : il se lie aux variables grce aux oprateurs =~ et !~. Les oprateurs =~ et !~, dcrits au chapitre 3, Oprateurs unaires et binaires, lient lexpression scalaire leur gauche lun des trois oprateurs de type apostrophes (ou guillemets) leur droite : m// pour rechercher un motif, s/// pour substituer une chane une sous-chane correspondant au motif et tr/// (ou son synonyme, y///) pour traduire un ensemble de caractres en un autre ensemble de caractres. (Vous pouvez crire // pour m// sans le m si les slash sont utiliss comme dlimiteurs.) Si la partie droite

customer_8566

128

Chapitre 5 Recherche de motif

de =~ ou !~ nest aucune de ces trois l, elle compte toujours comme une opration m/// de recherche, mais il ny a pas la place de mettre un seul modificateur final (voir plus loin la section Modificateurs de motif) et vous devrez grer vos propres apostrophes :
print "correspond" if $unechaine =~ $unmotif;

Vraiment, il ny a pas de raison de ne pas lcrire explicitement :


print "correspond" if $unechaine =~ m/$unmotif/;

Quand ils sont utiliss pour une recherche de correspondance, =~ et !~ se prononcent parfois respectivement correspond et ne correspond pas (bien que contient et ne contient pas puissent tre plus clair). Hormis les oprateurs m// et s///, les expressions rgulires apparaissent deux autres endroits dans Perl. Le premier argument de la fonction splitest une forme spciale de loprateur de correspondance spcifiant les parties ne pas retourner quand on dcoupe une chane en plusieurs sous-chanes. Voir la description de split et les exemples au chapitre 29, Fonctions. Loprateur qr// (quote regex) spcifie galement un motif laide dune regex, mais il nessaie pas de faire une correspondance avec quoi que ce soit (contrairement m//, qui le fait). Au lieu de cela, il retourne une forme compile de la regex pour une utilisation ultrieure. Voir Interpolation de variables pour plus dinformations. Vous appliquez lun des oprateurs m//, s/// ou tr/// une chane particulire avec loprateur de lien =~ (qui nest pas un vritable oprateur, mais plutt un indicateur du sujet de lopration). Voici quelques exemples :
$meuledefoin =~ m/aiguille/ $meuledefoin =~ /aiguille/ # cherche un motif simple # pareil

$italiano =~ s/beurre/huile dolive/ # une substitution bonne pour la sant $rotate13 =~ tr/a-zA-Z/n-za-mN-ZA-M/ # encryption simple ( casser)

Sans oprateur de lien, cest $_ qui est implicitement utilis comme "sujet" :
/nouvelles vies/ and # explore $_ et (si on trouve quelque chose) /autres civilisations/ # au mpris du danger, explore encore $_ s/sucre/aspartame/ tr/ATCG/TAGC/ # substitue un substitut dans $_ # complmente le brin dADN dans $_

Comme s/// et tr/// modifient le scalaire auquel ils sont appliqus, vous ne pouvez les utiliser quavec des lvalues valides :
"onshore" =~ s/on/off/; # FAUX : erreur la compilation

En revanche, m// fonctionne sur le rsultat de nimporte quelle expression scalaire :


if ((lc $chapeau_magique->contenu->comme_chaine) =~ /lapin/) { print "Euh, quoi dneuf, docteur ?\n"; } else { print "Ce tour ne marche jamais !\n"; }

Mais vous devez tre un petit peu prudent, car =~ et !~ ont une prcdence assez leve (dans notre exemple prcdent les parenthses sont ncessaires autour du terme de gau-

customer_8566

Oprateurs de recherche de motifs

129

che).4 Loprateur de lien !~ fonctionne comme =~, mais inverse la logique du rsultat de lopration :
if ($romance !~ /parole/) { print qq/"$romance" semble tre une romance sans parole.\n/; }

Comme m//, s/// sont des oprateurs apostrophes (ou guillemets), vous pouvez choisir vos dlimiteurs. Ils fonctionnent de la mme faon que les oprateurs de citation q//, qq//, qr//, et qw// (voir la section Choisissez vos dlimiteurs, chapitre 2, Composants de Perl).
$path =~ s#/tmp#/var/tmp/scratch#; if ($dir =~ m[/bin]) { print "Pas de rpertoires de binaires, sil vous plait.\n"; }

Quand vous utilisez des dlimiteurs apparis avec s/// ou tr///, si la premire partie utilise lune des quatre paires usuelles dencadrement (parenthses, crochets, accolades ou chevrons), vous pouvez choisir des dlimiteurs diffrents des premiers pour la seconde partie :
s(oeuf)<larve>; s{larve}{chrysalide}; s[chrysalide]/imago/;

Les blancs sont autoriss avant les dlimiteurs ouvrants :


s (oeuf) <larve>; s {larve} {chrysalide}; s [chrysalide] /imago/;

chaque fois quun motif correspond avec succs (y compris les motifs de substitution), il affecte aux variables $`, $& et $ le texte gauche de la correspondance, le texte correspondant et le texte droite de la correspondance. Cest utile pour sparer les chanes en leurs lments :
"pain print print print print au chocolat" =~ /au/; "Trouv : <$`> $& <$>\n"; "Gauche : <$`>\n"; "Correspondance : <$&>\n"; "Droite : <$>\n"; # Trouv : <pain > au < chocolat> # Gauche : <pain > # Correspondance : <au> # Droite : < chocolat>

Pour plus defficacit et de contrle, utilisez des parenthses pour capturer les portions spcifiques que vous voulez conserver. Chaque paire de parenthses capture la souschane correspondant au sous-motif entre parenthses. Les paires de parenthses sont numrotes de gauche droite par la position de chaque parenthse ouvrante. Une fois la correspondance tablie, les sous-chanes correspondantes sont disponibles dans les variables numrotes $1, $2, $3 et ainsi de suite :5

4. Sans les parenthses, le lc de moindre prcdence se serait appliqu toute la correspondance de motif plutt quau seul appel de mthode sur le chapeau de magicien. 5. Pas $0 cependant, qui contient le nom de votre programme.

customer_8566

130
$_ = "Bilbon Sacquet est n le 22 Septembre"; /(.*) est n le (.*)/; print "Personne: $1\n"; print "Date: $2\n";

Chapitre 5 Recherche de motif

$`, $&, $ et les variables numrotes sont implicitement localises dans la porte dynamique les contenant. Elles durent jusqu la prochaine recherche russie ou jusqu la fin de la porte courante, selon ce qui arrive en premier. Nous en reparlerons plus tard, dans un cadre diffrent. Une fois que Perl a dtect que vous aurez besoin de lune des variables $`, $& ou $ quelque part dans votre programme, il les fournira pour chaque correspondance. Cela va ralentir un peu votre programme. Comme Perl utilise un mcanisme semblable pour produire $1, $2et les autres, pour chaque motif contenant des parenthses de capture vous payez un peu en performance. (Voir Regroupement pour viter le cot de la capture en conservant la possibilit de regrouper.) Si vous nutilisez jamais $`, $& ou $, alors les motifs sans parenthses ne seront pas pnaliss. Si vous pouvez, il vaut donc mieux en gnral viter dutiliser $`, $& et $, en particulier dans les modules de bibliothque. Mais si vous devez les utiliser au moins une fois (et certains algorithmes apprcient vraiment leur commodit), alors utilisez-les autant que vous voulez, car vous avez dj pay le prix. $& nest pas aussi coteux que les deux autres dans les versions rcentes de Perl.

Modificateurs de motif
Nous allons discuter des diffrents oprateurs de recherche de motif dans un moment, mais nous aimerions dabord parler dun de leur points communs tous : les modificateurs. Vous pouvez placer un ou plusieurs modificateurs dune lettre immdiatement aprs le dlimiteur final, dans nimporte quel ordre. Par souci de clart, les modificateurs sont souvent appels le modificateur /o et prononcs le modificateur slash oh , mme si le modificateur final peut tre autre chose quun slash. (Certaines personnes disent drapeau ou option pour modificateur . Cest bien aussi.) Certains modificateurs changent le comportement dun seul oprateur, aussi les dcrirons-nous en dtail plus loin. Dautres changent la faon dont la regex est interprte. Les oprateurs m//, s/// et qr//6 acceptent tous les modificateurs suivants aprs le dlimiteur final :
Modificateur /i /s /m /x /o Signification Ignore les distinctions de casse des caractres (insensible la casse). Fait correspondre . avec le saut de ligne et ignore la variable obsolte $*. Fait correspondre ^ et $ ct dun \n intrieur. Ignore (la plupart) des blancs et autorise les commentaires dans le motif. Ne compile le motif quune seule fois.

6. Loprateur tr/// ne prend pas de regex, aussi ces modificateurs ne sy appliquent pas.

customer_8566

Oprateurs de recherche de motifs

131

Le modificateur /i indique de faire la correspondance la fois en majuscules et en minuscules (et en casse de titre en Unicode). Ainsi /perl/i correspondrait avec SUPERLATIF ou Perlimpinpin (entre autres choses). Le pragma use locale peut aussi avoir une inf luence sur ce qui est considr comme quivalent. (Cela peut avoir une mauvaise inf luence sur les chanes contenant de lUnicode.) Les modificateurs /s et /m nimpliquent rien de coquin. Ils affectent la manire dont Perl traite les correspondances avec des chanes contenant des sauts de ligne. Ils nindiquent pas si votre chane contient rellement des sauts de ligne ; mais plutt si Perl doit supposer que votre chane contient une seule ligne (/s) ou plusieurs lignes (/m), car certains mtacaractres fonctionnent diffremment selon quils sont censs se comporter dune manire oriente ligne ou non. Dordinaire le mtacaractre . correspond tout caractre sauf un saut de ligne, parce que sa signification traditionnelle est de correspondre aux caractres lintrieur dune ligne. Avec un /s cependant, le mtacaractre . peut aussi correspondre des sauts de ligne, car vous avez dit Perl dignorer le fait que la chane contient plusieurs sauts de ligne. (Le modificateur /s fait aussi ignorer Perl la variable obsolte $*, dont nous esprons que vous lignoriez aussi.) Le modificateur /m, de son ct, change linterprtation des mtacaractres ^ et $ en leur permettant de correspondre ct de sauts de lignes lintrieur de la chane au lieu de considrer seulement les extrmits de la chane. Voir les exemples dans la section Positions plus loin dans ce chapitre. Le modificateur /o contrle la recompilation des motifs. Sauf si les dlimiteurs sont des apostrophes simples, (mMOTIF, sMOTIFREMPLACEMENT, ou qrMOTIF), toute variable dans le motif sera interpole (et pourra provoquer la recompilation du motif) chaque fois que loprateur de motif sera valu. Si vous voulez quun motif ne soit compil quune fois et une seule, servez-vous du modificateur /o. Cela empche une recompilation coteuse lexcution ; cela peut servir quand la valeur interpole ne change pas au cours de lexcution. Cependant, utiliser /o revient faire la promesse de ne pas modifier les variables dans le motif. Si vous les modifiez, Perl ne sen rendra mme pas compte. Pour avoir un meilleur contrle de la recompilation des motifs, utilisez loprateur de citation de regex qr//. Pour plus de dtails, voir la section Interpolation de variables plus loin dans ce chapitre. Le modificateur /x est lexpressif : il vous permet dexploiter les blancs et les commentaires explicatifs pour exalter la lisibilit de votre motif, ou mme lui permettre dexplorer au-del des limites des lignes. Euh, cest--dire que /x modifie la signification des blancs (et du caractre #) : au lieu de les laisser se correspondre eux-mmes comme le font les caractres ordinaires, il les transforme en mtacaractres qui, trangement, se comportent comme les blancs (et les caractres de commentaires) devraient le faire. /x permet donc lutilisation despaces, de tabulations et de sauts de lignes pour le formatage, exactement comme le code Perl habituel. Il permet galement lutilisation du caractre #, qui nest normalement pas un caractre spcial dans un motif, pour introduire un commentaire qui stend jusquau bout de la ligne en cours lintrieur de la chane de motif.7 Si vous voulez dtecter un vritable espace (ou le caractre #), alors vous devrez le mettre dans une classe de caractres, le protger avec un antislash ou bien lencoder en octal ou en hexadcimal. (Mais les blancs sont normalement dtects avec une squence \s* ou \s+, donc la situation ne se rencontre pas souvent en pratique.)

customer_8566

132

Chapitre 5 Recherche de motif

elles toutes, ces fonctionnalits font beaucoup pour rendre les expressions rgulires plus proches dun langage lisible. Dans lesprit de TMTOWTDI, il existe donc plus dune manire dcrire une mme expression rationnelle. En fait, il y a plus de deux manires :
m/\w+:(\s+\w+)\s*\d+/; chiffres. m/\w+: (\s+ \w+) \s* \d+/x; chiffres. m{ \w+: ( \s+ \w+ ) \s* \d+ }x; # # # # # # # Dtecte un mot et un deux-points. (dbut de groupe) Dtecte un ou plusieurs blancs. Dtecte un autre mot. (fin de groupe) Dtecte zro ou plusieurs blancs. Dtecte des chiffres. # Mot, deux-points, espace, mot, espace,

# Mot, deux-points, espace, mot, espace,

Nous expliquerons ces nouveaux mtasymboles plus loin dans ce chapitre. (Cette section tait suppose dcrire les modificateurs de motifs, mais nous lavons laisser driver dans notre excitation au sujet de /x. Bref.) Voici une expression rgulire qui trouve les mots doubls dans un paragraphe, emprunt Perl en action (The Perl Cookbook). Il utilise les modificateurs /x et /i, ainsi que le modificateur /g dcrit plus loin.
# Trouve les doublons dans les paragraphes, si possible malgr les # enjambements. # Utilise /x pour les espaces et les commentaires, / pour dtecter les # deux tout dans "Tout tout va bien ?", et /g pour trouver tous les # doublons. $/ = ""; # mode "paragrep" while (<>) { while ( m{ \b # commence une limite de mot (\w\S+) # trouve un morceau de "mot" ( \s+ # spar par des blancs \1 # et ce mme morceau ) + # ad lib \b # jusqu une autre limite de mot }xig ) { print "doublon $1 au paragraphe $.\n"; } }
7. Faites attention cependant ne pas inclure le dlimiteur de motif dans le commentaire. cause de sa rgle "trouve la fin dabord", Perl na aucun moyen de savoir que vous naviez pas lintention de finir le motif cet endroit.

customer_8566

Oprateurs de recherche de motifs


Quand on lexcute sur ce chapitre, il affiche des avertissements tels que :
doublon nous au paragraphe 36

133

Bien sr, nous nous sommes aperus que dans ce cas particulier cest normal.

Loprateur m// (match)


EXPR =~ m/MOTIF/cgimosx EXPR =~ /MOTIF/cgimosx EXPR =~ ?MOTIF?cgimosx m/MOTIF/cgimosx /MOTIF/cgimosx ?MOTIF?cgimosx Loprateur m// recherche dans la chane contenue dans le scalaire EXPR le motif MOTIF. Si le dlimiteur est /ou ?, le m initial est facultatif. ? et ont tous deux une signification particulire en tant que dlimiteurs : le premier fait une dtection usage unique, le second supprime linterpolation de variables et les six squences de traduction (\U et autres, dcrits plus loin). Si lvaluation de MOTIF conduit une chane vide, soit parce que vous lavez spcifi ainsi en utilisant // ou parce quune variable interpole a donn la chane vide, la dernire expression rgulire excute avec succs sans tre cache lintrieur dun bloc inclus (ou lintrieur dun split, grep ou map) est excute la place. En contexte scalaire, loprateur renvoie vrai (1) en cas de succs, et faux ("") sinon. Cette forme se rencontre habituellement en contexte boolen :
if ($comte =~ m/Sacquet/) { ... } # recherche Sacquet dans la $comt if ($comte =~ /Sacquet/) { ... } # recherche Sacquet dans la $comt if ( m#Sacquet# ) if ( /Sacquet/ ) { ... } # cherche ici dans $_ { ... } # cherche ici dans $_

Utilis en contexte de liste, m// renvoie la liste des sous-chanes dtectes par les parenthses de capture du motif (cest--dire $1, $2, $3 et ainsi de suite), comme cela est dcrit plus loin dans la section Capture et regroupement. Les variables numrotes sont modifies malgr tout, mme si la liste est retourne. Si la recherche russit en contexte de liste mais quil ny avait pas de parenthses de capture (ni de /g), une liste consistant en (1) est retourne. Comme elle renvoie la liste vide en cas dchec, cette forme de m// peut aussi tre utilise en contexte boolen, mais seulement quand elle y participe indirectement via une affectation de liste :
if (($cle,$valeur) = /(\w+): (.*)/) { ... }

Les modificateurs valides pour m// (sous toutes ses formes) sont lists dans le tableau 5-1. Les cinq premiers modificateurs sappliquent la regex et ont t dcrits prcdemment. Les deux derniers modifient le comportement de loprateur lui-mme. Le modificateur /g indique une dtection globale cest--dire que lon recherche autant de fois quil est possible lintrieur de la chane. La faon dont cela se comporte dpend du contexte. En contexte de liste, m//g renvoie la liste de toutes les occurrences trouves. Dans lexemple suivant nous trouvons toutes les endroits o quelquun a mentionn perl , Perl , PERL , et ainsi de suite :

customer_8566

134
Tableau 5-1. Modificateurs de m//
Modificateur /i /m /s /x /o /g /cg Signification Ignore la casse des caractres.

Chapitre 5 Recherche de motif

Permet ^ et $ de fonctionner ct dun \n. Permet au . de dtecter des sauts de lignes et ignore la variable obsolte $*. Ignore (presque tous) les blancs et permet les commentaires lintrieur du motif. Compile le motif une seule fois. Recherche globale, pour dtecter toutes les occurrences. Permet de continuer la recherche aprs un chec dans /g.

if (@perls = $paragraphe =~ /perl/gi) { printf "Perl a t mentionn %d fois.\n", scalar @perls; }

Sil ny a pas de parenthses de capture dans le motif /g, alors les correspondances compltes sont renvoyes. Sil y a des parenthses de capture, seules les chanes captures sont retournes. Imaginez une chane comme celle-ci :
$chaine = "password=xyzzy verbose=9 score=0";

Imaginez galement que vous souhaitez initialiser un hachage comme ceci :


%hash = (password => "xyzzy", verbose => 9, score => 0);

Sauf videmment que vous navez pas une liste, vous avez une chane. Pour obtenir la liste correspondante, vous pouvez utiliser loprateur m//g en contexte de liste pour capturer tous les couples cl/valeur de la chane :
%hash = $chaine =~ /(\w+)=(\w+)/g;

La squence (\w+) capture un mot alphanumrique. Voir la section Capture et regroupement. Utilis en contexte scalaire, le modificateur /g indique une dtection progressive, qui reprend une nouvelle recherche sur la mme chane la position qui suit celle o la dernire sest arrte. Lassertion \G reprsente cette position dans la chane. Voir la section Positions plus loin dans ce chapitre pour une description de \G. Si vous utilisez le modificateur /c (pour continuer ) en plus de /g, alors quand le /g ne dtecte plus rien, la dtection rate ne rinitialise pas le pointeur de position. Si le dlimiteur est ?, comme dans ?MOTIF?, la recherche fonctionne comme un /MOTIF/ normal, sauf quelle ne trouve quune seule occurrence entre deux appels loprateur reset. Cela peut tre une optimisation utile, quand vous dsirez dtecter seulement la premire occurrence du motif pendant lexcution du programme, et pas toutes les occurrences. Loprateur fait la recherche chaque fois que vous lappelez, jusqu ce quil trouve finalement quelque chose, la suite de quoi il se bloque de lui-mme, renvoyant faux jusqu ce que vous le renclenchiez avec reset. Perl se souvient de ltat de la dtection pour vous. Loprateur ?? est particulirement utile quand une recherche de motif ordinaire trouverait la dernire occurrence plutt que la premire :

customer_8566

Oprateurs de recherche de motifs

135

open DICT, "/usr/dict/words_fr" or die "Impossible douvrir words_fr: $!\n"; while (<DICT>) { $premier = $1 if ?(^neur.*)?; $dernier = $1 if /(^neur.*)/; } print $premier,"\n"; # affiche "neural" print $dernier,"\n"; # affiche "neurula"

Loprateur reset ne rinitialisera que les instances de ?? qui ont t compiles dans le mme paquetage que lappel reset. m?? et ?? sont quivalents.

Loprateur s/// (substitution)


LVALUE =~ s/MOTIF/REMPLACEMENT/egimosx s/MOTIF/REMPLACEMENT/egimosx Cet oprateur recherche MOTIF dans une chane, et sil le dtecte, remplace la chane correspondante par le texte de REMPLACEMENT. (Les modificateurs sont dcrits plus loin dans cette section.)
$lotr = $hobbit; # Copie juste Bilbon le hobbit $lotr =~ s/Bilbon/Frodon/g; # et crit trs simplement une suite.

La valeur de retour dun s/// (en contexte scalaire comme en contexte de liste) est le nombre de fois quil a russit (ce qui peut tre plus dune fois sil a t utilis avec le modificateur /g dcrit plus tt). En cas dchec, il renvoie faux (""), qui est numriquement quivalent 0.
if ($lotr =~ s/Bilbon/Frodon/) { print "Suite crite avec succs." } $changements = $lotr =~ s/Bilbon/Frodon/g;

La partie de remplacement est traite comme une chane entre apostrophes doubles. Vous pouvez utiliser toutes les variables porte dynamique dcrites plus tt ($`, $&, $, $1, $2, et ainsi de suite) dans la chane de remplacement, ainsi que tous les trucs utilisables avec des apostrophes doubles. Voici un exemple qui trouve toutes les chanes revision , version , ou release , et les remplace chacune par son quivalent avec une majuscule, laide de la squence dchappement \u dans la partie de remplacement :
s/revision|version|release/\u$&/g; # Utilisez | pour dire "ou" # dans un motif

Toutes les variables scalaires sont interpoles en contexte dapostrophes doubles, et pas seulement les tranges que nous venons de voir. Supposons que vous ayez un hachage %Noms qui fasse correspondre aux numros de version des noms de projet interne ; par exemple $Noms{"3.0"} pourrait avoir le nom de code Isengard . Vous pourriez utiliser s/// pour trouver les numros de version et les remplacer par le nom des projets correspondants :
s/version ([0-9.]+)/la livraison $Noms{$1}/g;

Dans la chane de remplacement, $1 retourne ce que la premire (et unique) paire de parenthses a captur. (Vous auriez pu aussi utiliser \1 comme vous lauriez fait dans le motif, mais cet emploi est obsolte dans le remplacement. Dans une chane entre apostrophes doubles normale, \1 signifie Contrle-A.)

customer_8566

136

Chapitre 5 Recherche de motif

Si MOTIF est une chane vide, la dernire expression rgulire excute avec succs est utilise la place. MOTIF et REMPLACEMENT sont tous deux sujets linterpolation de variables. Cependant, un MOTIF est interpol chaque valuation du s/// en tant que tel, tandis que le REMPLACEMENT nest valu qu chaque fois quune correspondance est trouve. (Le MOTIF peut correspondre plusieurs fois en une valuation si vous utilisez le modificateur /g.) Comme prcdemment, les cinq modificateurs du tableau 5-2 modifient le comportement de la regex ; ce sont les mmes que pour m// et qr//. Les deux derniers affectent loprateur de substitution lui-mme. Tableau 5-2. Modificateurs de s///
Modificateur /i /m /s /x /o /g /e Signification Ignore la casse des caractres (lors de la correspondance). Permet ^ et $ de fonctionner ct dun \n. Permet au . de dtecter des sauts de ligne et ignore la variable obsolte $*. Ignore (presque tous) les blancs et permet les commentaires lintrieur du motif. Compile le motif une seule fois. Replacement global, cest--dire de toutes les occurrences. value la partie droite comme une expression.

Le modificateur /g est utilis avec s/// pour remplacer chaque occurrence de MOTIF par la valeur REMPLACEMENT, et pas seulement la premire rencontre. Un oprateur s///g agit comme un rechercher-remplacer global, en faisant toutes les modifications en une seule fois. Tout comme un m//g en contexte de liste, sauf que m//g ne change rien. (Et que s///g ne fait pas de dtection progressive comme le faisait un m//g en contexte scalaire.) Le modificateur /e traite le REMPLACEMENT comme sil sagissait dun bout de code Perl plutt que dune chane interpole. Le rsultat de lexcution de ce code est utilis comme chane de remplacement. Par exemple, s/([0-9]+)/sprintf("%#x", $1)/ge remplacerait 2581 par 0xb23. Ou supposez que dans notre exemple prcdent, vous nayez pas t sr de disposer dun nom pour toutes les versions et que vous ayez voulu laisser inchanges les versions sans nom. Avec un formatage un peu cratif de /x, vous auriez pu crire :
s{ version \s+ ( [0-9.]+ ) }{ $Noms{$1} ? "la livraison $Names{$1}" : $& }xge;

customer_8566

Oprateurs de recherche de motifs

137

La partie droite de votre s///e (ou dans ce cas, la partie basse) est vrifie syntaxiquement et compile en mme temps que le reste de votre programme. Toute erreur de syntaxe est dtecte la compilation, et les exceptions dynamiques ne sont pas releves. Chaque nouveau /e ajout la suite du premier (comme /ee, /eee et ainsi de suite) revient appeler eval CHAINE sur le rsultat du code, une fois par /e supplmentaire. Ceci value le rsultat du code dans lexpression et capture les exceptions dans la variable spciale $@. Voir la section Motifs programmatiques plus loin dans ce chapitre pour plus de dtails.

Modifier les chanes en passant


Parfois vous voulez une nouvelle chane, modifie sans altrer celle sur laquelle elle est base. Au lieu dcrire :
$lotr = $hobbit; $lotr =~ s/Bilbon/Frodon/g;

vous pouvez combiner ces deux instructions en une seule. cause de la prcdence, des parenthses sont requises autour de laffectation, tout comme dans la plupart des combinaisons appliquant =~ une expression.
($lotr = $hobbit) =~ s/Bilbon/Frodon/g;

Sans les parenthses autour de laffectation, vous nauriez fait que changer $hobbit et rcuprer le nombre de modifications dans $lotr, ce qui nous aurait donn une suite fort peu intressante. Vous ne pouvez pas utiliser un oprateur s/// directement sur un tableau. Pour cela, vous aurez besoin dune boucle. Par une heureuse concidence, lidiome Perl standard pour rechercher et modifier sur chaque lment dun tableau sobtient grce au systme dalias de for/foreach, combin avec lutilisation de $_ comme variable par dfaut de la boucle :
for (@chapitres) { s/Bilbon/Frodon/g } # Fait les substitutions chapitre # par chapitre. s/Bilbon/Frodon/g for @chapitres; # Pareil.

Comme avec les variables scalaires, vous pouvez galement combiner substitution et affectation si vous dsirez conserver une copie de loriginal :
@anciens = (oiseau bleu, bleu roi, bleu nuit, bleu de travail); for (@nouveaux = @anciens) { s/bleu/rouge/ } print "@nouveaux\n"; # affiche : oiseau rouge rouge roi rouge # nuit rouge de travail

La manire idiomatique dappliquer des substitutions rptes sur une mme variable est dutiliser une boucle un seul tour. Par exemple, voici comment normaliser les blancs dans une variable :
for ($chaine) { s/^\s+//; s/\s+$//; s/\s+/ /g; } # supprime les blancs au dbut # supprime les blancs la fin # minimise les blancs internes

customer_8566

138
ce qui produit exactement le mme rsultat que :
$chaine = join(" ", split " ", $chaine);

Chapitre 5 Recherche de motif

Vous pouvez galement utiliser une telle boucle dans une affectation, comme nous lavons fait dans le cas du tableau :
for ($nouveau = $ancien) { s/Fred/Homer/g; s/Wilma/Marge/g; s/Pebbles/Lisa/g; s/Dino/Bart/g; }

Quand une substitution globale nest pas assez globale


De temps en temps, vous ne pouvez tout simplement pas utiliser un /g pour que tous les changements soient faits, soit parce que les substitutions se produisent de droite gauche, soit parce que la longueur de $` doit changer entre deux occurrences. En gnral, vous pouvez faire cela en appelant s/// rptition. Mais vous voulez tout de mme que la boucle sarrte quand le s/// finit par chouer, ce qui ne laisse rien faire dans la partie principale de la boucle. Alors nous crivons un simple 1, qui est une chose plutt ennuyeuse faire, mais souvent le mieux que vous pouvez esprer. Voici quelques exemples qui utilisent quelques unes des ces tranges bestioles que sont les regex :
# met des points aux bons endroits dans un entier 1 while s/(\d)(\d\d\d)(?!\d)/$1.$2/; # change les tabulations pour des espacements sur 8 colonnes 1 while s/\t+/ x (length($&)*8 - length($`)%8)/e; # supprime les parenthses (imbriques (ou mme trs imbriques (comme a))) 1 while s/\([^()]*\)//g; # supprime les doublons (et les triplons (et les quadruplons...)) 1 while s/\b(\w+) \1\b/$1/gi;

Cette dernire ncessite une boucle car sinon elle transformerait ceci :
Paris AU AU AU AU printemps.

en cela :
Paris AU AU printemps.

Loprateur tr/// (translittration)


LVALUE =~ tr/LISTEDERECHERCHE/LISTEDEREMPLACEMENT/cds tr/LISTEDERECHERCHE/LISTEDEREMPLACEMENT/cds Pour les fans de sed, y/// est fourni comme synonyme de tr///. Cest la raison pour laquelle vous ne pouvez pas plus appeler une fonction y que vous ne pouvez lappeler q ou m. Hormis cela, y/// est exactement identique tr/// et nous ne le mentionnerons plus.

customer_8566

Oprateurs de recherche de motifs

139

Cet oprateur naurait pas vraiment de raison dapparatre dans un chapitre consacr la dtection de motif, puisquil nutilise pas de motif. Cet oprateur balaie une chane caractre par caractre, et remplace chaque occurrence dun caractre de LISTEDERECHERCHE (qui nest pas une expression rgulire) par le caractre correspondant dans LISTEDEREMPLACEMENT (qui nest pas une chane de remplacement). Cependant, il ressemble un peu m// et s///, et vous pouvez mme utiliser les oprateurs de lien =~ et !~ dessus. Cest pourquoi nous le dcrivons ici. (qr// et split sont des oprateurs de recherche de motif, mais on ne peut pas utiliser les oprateurs de lien dessus, cest pourquoi ils sont ailleurs dans ce livre. Allez comprendre.) La translittration retourne le nombre de caractres remplacs ou effacs. Si aucune chane nest spcfie par les oprateurs =~ ou !~, cest la chane $_ qui est modifie. LISTEDERECHERCHE et LISTEDEREMPLACEMENT peuvent dfinir des intervalles de caractres successifs laide dun tiret :
$message =~ tr/A-Za-z/N-ZA-Mn-za-m/; # cryptage rot13.

Remarquez quun intervalle comme A-Z suppose un ensemble de caractres linaire comme lest la table ASCII. Mais chaque ensemble de caractres a son propre point de vue concernant lordre de ses caractres, et donc de quels caractres font partie dun intervalle particulier. Un principe sain est dutiliser des intervalles qui commencent et finissent sur des caractres de la mme casse (a-e, A-E) ou des chiffres (0-4). Tout le reste est suspect. En cas de doute, dcrivez lensemble qui vous intresse en entier : ABCDE. LISTEDERECHERCHE et LISTEDEREMPLACEMENT ne subissent pas dinterpolation de variable comme des chanes entre apostrophes doubles ; vous pouvez cependant utiliser les squences avec antislash qui correspondent des caractres spcifiques, comme \n ou \015. Le tableau tableau 5-3 donne la liste des modificateurs qui sappliquent loprateur tr///. Ils sont compltement diffrents de ceux que vous appliquez m//, s/// ou qr//, mme si certains dentre eux y ressemblent. Si le modificateur /c est spcifi, le jeu de caractres dans LISTEDERECHERCHE est complment ; cest--dire que la liste de recherche effective comprend tous les caractres qui ne se trouvent pas dans LISTEDERECHERCHE. Dans le cas de lUnicode, cela peut reprsenter un grand nombre de caractres, mais comme ils sont stocks logiquement et non physiquement, vous navez pas vous inquiter dun ventuel manque de mmoire. Tableau 5-3. Modificateurs de tr///
Modificateur /c /d /s Signification Complmente la LISTEDERECHERCHE. Supprime les caractres trouvs mais non remplacs. Concentre les caractres dupliqus remplacs.

Le modificateur /d transforme tr/// en ce quon pourrait appeler loprateur de transoblitration : tout caractre spcifi par LISTEDERECHERCHE mais qui na pas de caractre de remplacement dans LISTEDEREMPLACEMENT est effac. (Cest un peu plus souple que le comportement de certains tr(1), qui effacent tout ce quils trouvent dans LISTEDERECHERCHE, point.)

customer_8566

140

Chapitre 5 Recherche de motif

Si le modificateur /s est spcifi, les suites de caractres qui sont convertis en un caractre identique sont rduites un seul exemplaire de ce caractre. Si le modificateur /d est utilis, LISTEDEREMPLACEMENT est toujours interprte comme elle est spcifie. Sinon, si LISTEDEREMPLACEMENT est plus courte que LISTEDERECHERCHE, le dernier caractre est rpliqu jusqu ce quelle soit assez longue. Si LISTEDEREMPLACEMENT est vide, la LISTEDERECHERCHE est rplique, ce qui est tonnamment utile si vous voulez juste compter les caractres, et non les modifier. Cest aussi utile pour compacter les squences de caractres. avec /s.
tr/aeiou/!/; tr{/\\\r\n\b\f. }{_}; tr/A-Z/a-z/ for @ARGV; # change toutes les voyelles en ! # change les caractres bizarres en souligns # normalise en minuscules ASCII

$compte = ($para =~ tr/\n//); # compte les sauts de lignes dans $para $compte = tr/0-9//; # compte les chiffres dans $_ $mot =~ tr/a-zA-Z//s; tr/@$%*//d; tr#A-Za-z0-9+/##cd; # illettrisme -> iletrisme # supprime tous ceux l # supprime les caractres hors base64

# change en passant ($HOTE = $hote) =~ tr/a-z/A-Z/; $pathname =~ tr/a-zA-Z/_/cs; # change les caractres ASCII non # alphabtiques en un seul soulign tr [\200-\377] [\000-\177];

# supprime le 8e bit de chaque octet

Si le mme caractre apparat plusieurs fois dans la LISTEDERECHERCHE, seul le premier est utilis. Ainsi, ceci :
tr/AAA/XYZ/

changera tout A en X (dans $_). Bien que les variables ne soient pas interpoles par tr///, vous pouvez obtenir le mme effet en utilisant eval EXPR :
$compte = eval "tr/$ancien/$nouveau/"; die if $@; # propage lexception due un contenu de eval incorrect

Encore un mot : si vous voulez passer votre texte en majuscules ou en minuscules, nutilisez pas tr///. Utilisez plutt les squences \U ou \L dans des chanes entre apostrophes doubles (lquivalent des fonctions ucet lc) car elles seront attentives aux informations de locales et lUnicode, alors que tr/a-z/A-Z ne le sera pas. De plus, dans les chanes Unicode, la squence \u et la fonction correspondante ucfirst comprennent la notion de casse de titre, ce qui pour certaines langues peut tre diffrent de simplement convertir en majuscules.

customer_8566

Mtacaractres et mtasymboles

141

Mtacaractres et mtasymboles
Maintenant que nous avons admir les jolies cages, nous pouvons de nouveau nous intresser aux bestioles dans ces cages, les tranges caractres que vous mettez dans les motifs. Maintenant vous avez compris que ces symboles ne sont pas du code Perl normal comme les appels de fonction ou les oprateurs arithmtiques. Les expressions rgulires ont leur propre petit langage inclus dans Perl. (Chacun a son jardin et sa jungle secrte.) Malgr leur puissance et leur expressivit, les motifs de Perl reconnaissent les mmes 12 caractres traditionnels (les Douze salopards , sil en est) quon trouve dans de nombreux autres modules dexpressions rgulires.
\ | ( ) [ { ^ $ * + ? .

Certains dentre eux changent les rgles, rendant spciaux les caractres normaux qui les suivent. Nous naimons pas appeler les squences de plus dun caractre des caractres , cest pourquoi nous les appelerons mtasymboles (ou mme seulement symboles ). Mais au plus haut niveau, ces douze mtacaractres sont tout ce dont vous (et Perl) avez vous inquiter. Tout le reste procde de l. Certains mtacaractres simples fonctionnent par eux-mmes, comme ., ^ et $. Ils naffectent directement rien de ce qui les entoure. Certains mtacaractres fonctionnent commes des oprateurs prfixes, contrlant ce qui les suit, comme \. Dautres fonctionnent comme des oprateurs postfixes, et contrlent ce qui les prcde immdiatement, comme *, + et ?. Un mtacaractre, |, fonctionne comme un oprateur infixe, en se tenant entre les deux oprandes quil affecte. Il existe mme des mtacaractres de parenthsage, qui fonctionnent comme des oprateurs circonfixes , et rgissent ce quils contiennent, comme (...) et [...]. Les parenthses sont particulirement importantes, car elles dfinissent les limites de | lintrieur, et celles de *, + et ? lextrieur. Si vous napprenez quun seul des douze mtacaractres, choisissez lantislash. (Euh... et les parenthses.) Cest parce que lantislash invalide les autres. Quand un antislash prcde un caractre non alphanumrique dans un motif Perl, il en fait toujours un caractre littral. Si vous avez besoin de faire une correspondance littrale avec lun des douze mtacaractres, vous navez qu lcrire prcde dun antislash. Ainsi, \. est un vrai point, \$ un vrai dollar, \\ un vrai antislash, et ainsi de suite. On appelle cela protger le mtacaractre, ou simplement l antislasher . (Bien sr, vous savez dj que lantislash sert supprimer linterpolation de variable dans les chanes entre apostrophes doubles.) Bien quun antislash transforme un mtacaractre en caractre littral, il a leffet inverse sur un caractre alphanumrique le suivant. Il prend ce qui tait normal et le rend spcial. Cest--dire qu eux deux, ils forment un mtasymbole. Une liste alphabtique de ces mtasymboles se trouve juste en dessous dans le tableau 5-7.

Tables de mtasymboles
Dans les tableaux qui suivent, la colonne Atomique indique Oui si le mtasymbole correspondant est quantifiable (cest--dire sil peut correspondre quelque chose qui a une largeur, plus ou moins). Nous avons galement utilis ... pour reprsenter

customer_8566

142

Chapitre 5 Recherche de motif

quelque chose dautre . (Consultez la discussion qui suit pour savoir ce que ... signifie, si le commentaire du tableau nest pas suffisant.) Le tableau 5-4 liste les mtasymboles traditionnels de base. Les quatre premiers sont les mtasymboles structurels dj mentionns, tandis que les trois suivants sont de simples mtacaractres. Le mtacaractre . est un exemple datome car il correspond quelque chose qui a une largeur (la largeur dun caractre, dans ce cas) ; ^ et $ sont des exemples dassertions, car ils correspondent quelque chose de largeur nulle et ne sont valus que pour savoir sils sont vrais ou faux. Tableau 5-4. Mtacaractres usuels de regex
Symbole \... ...|... (...) [...] ^ . $ Atomique Variable Non Oui Oui Non Oui Non Signification Rend le caractre non alphanumrique suivant littral, rend le caractre alphanumrique suivant mta (peut-tre). Alternative (correspond lun ou lautre). Regroupement (traite comme une unit). Classe de caractres (correspond un caractre dun ensemble). Vrai au dbut dune chane (ou aprs toute nouvelle ligne, ventuellement). Correspond un caractre (sauf le saut de ligne, normalement). Vrai en fin de chane (ou avant toute nouvelle ligne, ventuellement).

Les quantificateurs, dcrits plus loin dans leur propre section, indiquent combien de fois latome qui les prcde (caractre simple ou regroupement) doit correspondre. Ils sont lists dans le tableau 5-5. Tableau 5-5. Quantificateurs de regex
Quantificateur Atomique * + ? {COMPTE} {MIN,} {MIN,MAX} *? +? ?? {MIN,}? {MIN,MAX}? Non Non Non Non No No Non Non Non Non Non Signification Correspond 0 fois ou plus (maximal). Correspond 1 fois ou plus (maximal). Correspond 0 ou 1 fois (maximal). Correspond exactement COMPTE fois. Correspond au moins MIN fois (maximal). Correspond au moins MIN fois, mais pas plus de MAX fois (maximal). Correspond 0 fois ou plus (minimal). Correspond 1 fois ou plus (minimal). Correspond 0 ou 1 fois (minimal). Correspond au moins MIN fois (minimal). Correspond au moins MIN fois, mais pas plus de MAX fois (minimal).

customer_8566

Mtacaractres et mtasymboles

143

Un quantificateur minimal essaie de correspondre aussi peu que possible dans lintervalle autoris. Un quantificateur maximal essaie de correspondre le plus possible, dans lintervalle autoris. Par exemple, .+ est sr de correspondre au moins un des caractres de la chane, mais correspondra tous sil en a loccasion. Ces occasions seront dcrites plus loin dans Le petit Moteur qui /(ne )?pouvait( pas)?/ . Vous remarquerez quun quantificateur ne peut jamais tre quantifi. Nous voulions fournir une syntaxe extensible pour pouvoir introduire de nouveaux types de mtasymboles. tant donn que nous navions quune douzaine de mtacaractres notre disposition, nous avons choisi dutiliser une squence de regex anciennement incorrecte pour ces extensions syntaxiques arbitraires. Ces mtasymboles sont tous de la forme (?CLE...) ; cest--dire une parenthse (quilibre) suivie dun point dinterrogration, suivie par une CLE et le reste du sous-motif. Le caractre CLE indique de quelle extension de regex il sagit. Voyez le tableau 5-6 pour en avoir la liste. La plupart dentre eux se comportent bien structurellement, car ils sont bass sur des parenthses, mais ont galement une signification supplmentaire. De nouveau, seuls les atomes peuvent tre quantifis, car ils reprsentent quelque chose qui est vraiment l (potentiellement). Tableau 5-6. Squences de regex tendues
Extension (?#...) (?:...) (?imsx-imsx) (?imsx-imsx:...) (?=...) (?!...) (?<=...) (?<!...) (?>>...) (?{...}) (??{...}) (?(...)...|...) (?(...)...) Atomique Non Oui No Oui Non Non Non Non Yes Non Oui Oui Oui Signification Commentaire, ignor. Parenthses de regroupement seul, sans capture. Active/dsactive les modificateurs de motif. Parenthses de regroupement, et modificateurs. Vrai si lassertion de pr-vision est un succs. Vrai si lassertion de pr-vision est un chec. Vrai si lassertion de rtro-vision est un succs. Vrai si lassertion de rtro-vision est un chec. Correspond au motif sans retour arrire. Excute le code Perl inclus. Fait correspondre la regex du code Perl inclus. Correspond avec un motif si-alors-sinon. Correspond avec un motif si-alors.

Enfin, tableau 5-7 donne la liste de tous les mtasymboles alphanumriques usuels. (Les symboles qui sont traits durant la passe dinterpolation de variables sont indiqus avec un tiret dans la colonne Atomique, car le Moteur ne les voit jamais.) Les accolades sont facultatives pour \p et \P si le nom de la proprit fait un seul caractre. Les accolades sont facultatives pour \x si le nombre hexadcimal fait deux chiffres ou moins. Les accolades ne sont jamais facultatives pour \N.

customer_8566

144
Tableau 5-7. Mtasymboles alphanumriques de regex
Symbole \0 \NNN \n \a \A \b \b \B \cX \C \d \D \e \E \f \G \l \L \n \N{NAME} \p{PROP} \P{PROP} \Q \r \s \S \t \u \U \w Atomique Oui Oui Oui Oui Non Oui Non Non Oui Oui Oui Oui Oui Oui Non Oui Oui Oui Oui Oui Oui Oui Oui Oui Signification

Chapitre 5 Recherche de motif

Correspond au caractre nul (ASCII NUL). Correspond au caractre donn en octal, jusqu \377. Correspond la nime chane capture (en dcimal). Correspond au caractre alarme (BEL). Vrai au dbut dune chane. Correspond au caractre espace arrire (BS). Vrai une limite de mot. Vrai hors dune limite de mot. Correspond au caractre de contrle Contrle-X (\cZ, \c[, etc.). Correspond un octet (un char en C), mme en utf8 (dangereux). Correspond tout caractre numrique. Correspond tout caractre non numrique. Correspond au caractre dchappement (ASCII ESC, pas lantislash). Termine la traduction de casse (\L, \U) ou la citation de mtacaractres. Correspond au caractre de fin de page (FF). Vrai la position de fin de recherche du m//g prcdent. Passe le prochain caractre seulement en minuscules. Minuscules jusquau prochain \E. Correspond au caractre de saut de ligne (en gnral NL, mais CR sur les Mac). Correspond au caractre nomm (\N{greek:Sigma}). Correspond tout caractre ayant la proprit cite. Correspond tout caractre nayant pas la proprit cite. Cite les mtacaractres (dsactive leur ct mta) jusquau prochain \E. Correspond au caractre de retour chariot (CR en gnral, mais NL sur les Mac). Correspond tout caractre blanc. Correspond tout caractre non blanc. Correspond au caractre de tabulation (HT). Passe le prochain caractre seulement en grandes initiales. Passe en majuscules (et non en grandes initiales) jusquau prochain \E. Correspond tout caractre de mot (alphanumriques et _ ).

customer_8566

Mtacaractres et mtasymboles
Tableau 5-7. Mtasymboles alphanumriques de regex (suite)
Symbole \W \x{abcd} \X \z \Z Atomique Oui Oui Oui Non Non Signification Correspond tout caractre non mot . Correspond au caractre donn en hexadcimal.

145

Correspond une squence de caractres Unicode combins . Vrai seulement en fin de chane. Vrai en fin de chane ou avant un ventuel saut de ligne.

Seuls les mtasymboles dont la description est Correspond ... peuvent tre utiliss dans une classe de caractres. Cest--dire que les classes de caractres ne peuvent contenir que des ensembles spcifiques de caractres, et vous ne pouvez donc utiliser lintrieur que des mtasymboles qui dcrivent dautres ensembles spcifiques de caractres ou qui dcrivent des caractres individuels. Bien sr, ces mtasymboles peuvent aussi tre utiliss en dehors des classes de caractres, avec les autres mtasymboles (qui ne peuvent tre utiliss quhors classe). Remarquez cependat que \b est en fait deux bestioles compltement diffrentes : cest un espace arrire dans une classe de caractres, mais une assertion de limite de mot en dehors. Il y a un certain chevauchement entre les caractres auxquels un motif peut correspondre et les caractres quune chane entre apostrophes doubles peut interpoler. Comme les regex subissent deux passes, il est parfois ambigu de savoir quelle passe doit traiter quel caractre. Quand il y a une ambigut, la passe dinterpolation de variable dfre linterprtation de ces caractres lanalyseur dexpressions rgulires. Mais la passe dinterpolation de variable ne peut dfrer lanalyseur de regex que quand elle sait quelle est en train danalyser une regex. Vous pouvez spcifier des expressions rgulires comme des chanes entre apostrophes doubles ordinaires, mais vous devez alors suivre les rgles normales des apostrophes doubles. Chacun des mtasymboles prcdents qui correspond un caractre existant continuera de marcher, mme sil nest pas dfr lanalyseur de regex. Mais vous ne pourrez utiliser aucun des autres mtasymboles entre des apostrophes doubles ordinaires (ou dans toute construction analogue comme `...`, qq(...), qx(...) ou les documents ici-mme quivalents). Si vous voulez que votre chane soit analyse comme une expression rgulire sans faire de correspondance, vous devriez utiliser loprateur qr// (quote regex). Notez que les squences dchappement de casse et de mtacitation (\U et compagnie) doivent tre traits durant la passe dinterpolation, car leur rle est de modifier la faon dont les variables sont interpoles. Si vous supprimez linterpolation de variable avec des apostrophes simples, vous naurez pas non plus les squences dchappement. Ni les variables ni les squences dchappement (\U, etc.) ne sont tendues dans les chanes entre apostrophes simples, ni dans les oprateurs m... ou qr... avec apostrophes simples. Et mme si vous faites une interpolation, ces squences dchappement sont ignores si elles apparaissent dans le rsultat de linterpolation de variable, car ce moment-l il est trop tard pour inf luencer linterpolation de variable. Bien que loprateur de translittration ne prenne pas dexpression rgulire, tout mtasymbole prcdemment discut qui correspond un caractre spcifique simple mar-

customer_8566

146

Chapitre 5 Recherche de motif

che aussi dans une opration tr///. Les autres ne marchent pas (sauf bien sr lantislash qui continue toujours fonctionner sa manire bien lui).

Caractres spcifiques
Comme mentionn prcdemment, tout ce qui nest pas spcial dans un motif se correspond lui-mme. Cela signifie quun /a/ correspond un a , un /=/ correspond un = , et ainsi de suite. Certains caractres ne sont cependant pas trs faciles taper au clavier ou, mme si vous y arrivez ne safficheront pas lisiblement ; les caractres de contrle sont connus pour cela. Dans une expression rgulire, Perl reconnat les alias dapostrophes doubles suivants :
chappement \0 \a \e \f \n \r \t Signification Caractre nul (ASCII NUL) Alarme (BEL) chappement (ESC) Fin de page (FF) Saut de ligne (NL, CR sur Mac) Retour chariot (CR, NL sur Mac) Tabulation (HT)

Tout comme dans les chanes entre apostrophes doubles, Perl reconnat galement les quatre mtasymboles suivants dans les motifs : \cX Un caractre de contrle nomm, comme \cC pour Contrle-C, \cZ pour ContrleZ, \c[ pour ESC, et \c? pour DEL. \NNN Un caractre spcifi en utilisant son code octal deux ou trois chiffres. Le 0 initial est facultatif, sauf pour les valeurs infrieures 010 (8 en dcimal), car (contrairement aux chanes entre apostrophes doubles) les versions un seul chiffre sont toujours considres comme des rfrences arrires des chanes captures dans un motif. Les versions plusieurs chiffres sont interprtes comme la nime rfrence arrire si vous avez captur au moins n sous-chanes plus tt dans le motif (avec n considr comme un nombre dcimal). Sinon, elle est interprte comme un caractre octal. \x{HEXLONG} \xHEX Un caractre spcifi par son numro un ou deux chiffres hexadcimaux ([0-9afA-F]), comme \x1B. La forme un seul chiffre est utilisable quand le caractre suivant nest pas un chiffre hexadcimal. Si vous utilisez des accolades, vous pouvez mettre autant de chiffres que vous voulez, ce qui peut conduire un caractre Unicode. Par exemple, \x{262f} correspond un YIN YANG Unicode.

customer_8566

Mtacaractres et mtasymboles
\N{NOM}

147

Un caractre nomm, comme \N{GREEK SMALL LETTER EPSILON}, \N{greek:epsilon}, ou \N{epsilon}. Ceci requiert lutilisation du pragma use charnames dcrit au chapitre 31, Modules de pragmas, et qui dtermine aussi lequel de ces noms vous pouvez utiliser (":long", ":full", ":short" qui correspondent respectivement aux trois styles que nous venons de citer). Vous trouverez une liste de tous les noms de caractres Unicode dans vos documents de standard Unicode prfrs ou dans le fichier PATH_TO_PERLLIB/unicode/Names.txt.

Mtasymboles jokers
Trois mtasymboles spciaux sont utiliss comme des jokers gnriques, chacun dentre eux correspondant tout caractre (pour certaines valeurs de tout ). Ce sont le point ("."), \C et \X. Aucun dentre eux ne peut tre utilis dans une classe de caractres. Vous ne pouvez pas y utiliser le point car il correspondrait (presque) tout caractre existant. Cest donc dj une sorte de classe de caractres universelle par lui-mme. Si vous voulez tout inclure ou tout exclure, il ny a pas grand intrt utiliser une classe de caractres. Les jokers spciaux \C et \X ont une signification structurelle spcifique qui ne saccorde pas bien avec lide de choisir un seul caractre Unicode, ce qui est le niveau auquel fonctionne une classe de caractres. Le mtacaractre point correspond tout caractre autre que le saut de ligne. (Et avec le modificateur /s, il lui correspond aussi.) Comme chacun des autres caractres spciaux dans un motif, pour correspondre un point littral, vous devez le protger avec un antislash. Par exemple, ceci vrifie si un nom de fichier se termine par un point suivi dune extension un caractre :
if ($chemin =~ /\.(.)\z/s) { print "Se termine par $1\n"; }

Le premier point, celui qui est protg, est un caractre littral, tandis que le second dit correspond tout caractre . Le \z demande de ne correspondre qu la fin de la chane, et le modificateur /s permet au point de correspondre galement un saut de ligne. (Certes, utiliser un saut de ligne comme extension nest Pas Trs Gentil, mais cela ne veut pas dire que cela ne peut pas se produire.) Le mtacaractre point est le plus souvent utilis avec un quantificateur. Un .* correspond un nombre maximal de caractres, tandis quun .*? correspond un nombre minimal de caractres. Mais il est aussi utilis parfois sans quantificateur pour sa propre largeur : /(..):(..):(..)/ correspond trois champs spars par des deux-points, chacun faisant deux caractres de large. Si vous utilisez un point dans un motif compil sous le pragma porte lexicale use utf8, alors il correspondra tout caractre Unicode. (Vous ntes pas suppos avoir besoin de use utf8 pour cela, mais il y a toujours des accidents. Le pragma peut ne plus tre utile dici ce que vous lisiez ces lignes.)
use utf8; use charnames qw/:full/;

customer_8566

148

Chapitre 5 Recherche de motif

$BWV[887] = "G\N{MUSIC SHARP SIGN} minor"; # partition anglaise ($note, $noire, $mode) = $BWV[887] =~ /^([A-G])(.)\s+(\S+)/; eq chr(9839); print "Cest en dise !\n" if $n

Le mtasymbole \X correspond un caractre Unicode dans un sens plus tendu. Il correspond en fait une chane dun ou plusieurs caractres Unicode connue sous le nom de squence de caractres combins . Une telle squence consiste en un caractre de base suivi par lun des caractres de marquage (signe diacritique comme une cdille ou un trma) qui se combine avec le caractre de base pour former une unit logique. \X est exactement quivalent (?:\PM\pM*). Cela permet de correspondre un seul caractre logique, mme si celui est en fait constitu de plusieurs caractres distincts. La longueur de la correspondance de /\X/ peut excder un caractre si celui-ci a trouv des caractres combins. (Et nous parlons ici de la longueur en caractres, qui na pas grand chose voir avec la longueur en octets.) Si vous utilisez Unicode et que vous voulez vraiment travailler sur un seul octet plutt que sur un seul caractre, vous pouvez utiliser le mtasymbole \C. Ceci correspondra toujours un seul octet (spcifiquement, un seul lment de type char de C), mme si cela vous dsynchronise de votre f lux de caractres Unicode. Rfrez-vous aux avertissements relatifs cela au chapitre 15.

Classes de caractres
Dans une recherche de motif, vous pouvez tablir une correspondance avec tout caractre qui a ou na pas une proprit particulire. Il existe quatre manires de spcifier les classes de caractres. Vous pouvez spcifier une classe de caractres de la manire traditionnelle en utilisant des crochets et en numrant les caractres possibles, ou en utilisant lun des trois raccourcis mnmotechniques : les classes Perl habituelles, les nouvelles proprits Unicode de Perl ou les classes POSIX standard. Chacun de ces raccourcis correspond un seul caractre de son ensemble. Quantifiez-les si vous voulez faire une correspondance avec un plus grand nombre dentre eux, comme \d+ pour correspondre plusieurs chiffres. (Une erreur facile faire est de croire que \w correspond un mot. Utilisez \w+ pour trouver un mot.)

Classes de caractres personnalises


Une liste de caractres numre entre crochets est appele une classe de caractre et correspond tout caractre dans la liste. Par exemple, [aeiouy] correspond une voyelle (non accentue). Pour correspondre un crochet fermant, antislashez-le ou bien placezle en premier dans la liste. Des intervalles de caractres peuvent tre indiqus en utilisant un tiret et la notation az. Plusieurs intervalles peuvent tre combins ; par exemple [0-9a-fA-F]correspond un chiffre hexadcimal. Vous pouvez utiliser un antislash pour protger un tiret qui serait sinon interprt comme un dlimiteur dintervalle, ou simplement le placer en dbut de liste (une pratique probablement moins lisible mais plus traditionnelle). Un chapeau (ou accent circonf lexe, ou f lche vers le haut) au dbut de la classe de caractre linverse, la faisant correspondre tout caractre ne se trouvant pas dans la liste. (Pour correspondre un chapeau, ou bien ne le mettez pas au dbut, ou mieux, prot-

customer_8566

Classes de caractres

149

gez-le avec un antislash.) Par exemple, [^aeiouy] correspond tout caractre qui nest pas une voyelle (non accentue). Cependant soyez prudent avec la ngation de classe, car lunivers des caractres est en expansion. Par exemple, cette classe de caractre correspond aux consonnes et aussi aux espaces, aux sauts de ligne, et tout (y compris les voyelles) en cyrillique, en grec ou tout autre alphabet, sans compter tous les idogrammes chinois, japonais et corens. Et un jour aussi le cirth, le tengwar et le klingon. (Mais dj le linaire B et ltrusque.) Il vaut donc peut-tre mieux spcifier vos consonnes explicitement, comme [bcdfghjklmnpqrstvwxyz], ou [b-df-hj-np-tv-z] pour faire plus court. (Cela rsout aussi le problme du y qui devrait tre deux endroits la fois, ce quinterdit lutilisation de lensemble complmentaire.) Les mtasymboles caractres normaux, comme \n, \t, \cX, \NNN et \N{NOM} sont utilisables dans une classe de caractres (voir la section Caractres spcifiques). De plus, vous pouvez utiliser \b dans une classe de caractres pour signifier un espace arrire, exactement comme dans une chane entre apostrophes doubles. Normalement, dans une recherche de motif, il reprsente une limite de mot. Mais les assertions de largeur nulle nont aucun sens dans une classe de caractres, cest pourquoi \b retrouve la signification quil a dans les chanes. Vous pouvez galement utiliser les classes de caractres prdfinies qui sont dcrites plus loin dans ce chapitre (classique, Unicode ou POSIX), mais nessayez pas de les utiliser comme point initial ou final dun intervalle cela nayant pas de sens, le - sera interprt comme un caractre littral. Tous les autres mtasymboles perdent leur signification spciale quand ils sont entre crochets. En particulier, vous ne pouvez utiliser aucun des trois jokers gnriques : . , \Xou \C. Le premier surprend souvent, mais cela na pas grand sens dutiliser la classe de caractre universelle lintrieur dune classe plus restrictive, et de plus vous avez souvent besoin de faire une correspondance avec un point littral dans une classe de caractre quand vous travaillez sur des noms de fichier, par exemple. Cela na pas grand sens non plus de spcifier des quantificateurs, des assertions ou des alternatives dans une classe de caractres, puisque les caractres sont interprts individuellement. Par exemple, [fee|fie|foe|foo] a exactement la mme signification que [feio|].

Raccourcis de classes de caractres classiques Perl


Depuis lorigine, Perl a fourni un certain nombre de raccourcis pour les classes de caractres. La liste est fournie dans le tableau 5-8. Tous sont des mtasymboles alphabtiques antislashs, et dans chaque cas, la version en majuscule est la ngation de la version en minuscules. Leur signification est nest pas aussi rigide que vous pourriez le croire : leur sens peut tre inf luenc par les dfinitions de locales. Mme si vous nutilisez pas les locales, leur signification peut changer chaque fois quun nouveau standard Unicode sortira, ajoutant de nouveaux scripts avec de nouveaux chiffres et de nouvelles lettres. (Pour conserver lancienne signification par octets, vous pouvez toujours utiliser use bytes. Voir Proprits Unicode un peu plus loin dans ce chapitre pour des explications sur les correspondances utf8. Dans tous les cas, les correspondances utf8 sont un surensemble des correspondances sur les octets.) (Oui, nous savons que la plupart des mots ne comportent ni chiffres ni souligns mais parfois des accents ; \w sert trouver des mots au sens des tokens dans un langage de programmation usuel. Ou en Perl.)

customer_8566

150
Tableau 5-8. classe de caractres classiques
Symbole \d \D \s \S \w \W Signification Chiffre Non chiffre Blanc Non blanc Caractre de mot Non-(caractre mot) En octets [0-9] [^0-9]

Chapitre 5 Recherche de motif

En utf8 \p{IsDigit} \P{IsDigit} \p{IsSpace} \P{IsSpace} \p{IsWord} \P{IsWord}

[ \t\n\r\f] [^ \t\n\r\f] [a-zA-Z0-9_] [^a-zA-Z0-9_]

Ces mtacaractres peuvent tre utiliss lextrieur ou lintrieur de crochets, cest-dire soit par eux-mmes ou comme lment dune classe de caractres :
if ($var =~ /\D/) { warn "contient des non-chiffres" } if ($var =~ /[^\w\s.]/) { warn "contient des non-(mot, espace, point)" }

Proprits Unicode
Les proprits Unicode sont disponibles en utilisant \p{PROP} et son ensemble complmentaire \P{PROP}. Pour les rares proprits qui ont un nom en un seul caractre, les accolades sont facultatives, comme dans \pN pour indiquer un caractre numrique (pas ncessairement dcimal les chiffres romains sont aussi des caractres numriques). Ces classes de proprits peuvent tre utilises par elles-mmes ou combines dans une classe de caractres :
if ($var =~ /^\p{IsAlpha}+$/) { print "tout alphabtique" } if ($var =~ s/[\p{Zl}\p{Zp}]/\n/g) { print "saut de lignes" }

Certaines proprits sont directement dfinies dans le standard Unicode, et dautres sont des composes dfinies par Perl, en sappuyant sur les proprits standard. Zl et Zp sont des proprits Unicode standard qui reprsentent les sparateurs de lignes et de paragraphes, tandis quIsAlpha est dfinie par Perl comme une classe regroupant les proprits standard Ll, Lu, Lt et Lo (cest--dire les lettres qui sont en majuscules, en minuscules, en casse de titre ou autre). partir de la version 5.6.0 de Perl, vous avez besoin de use utf8 pour que ces proprits fonctionnent. Cette restriction sera assouplie dans le futur. Il y a un grand nombre de proprits. Nous allons lister celles que nous connaissons, mais la liste sera forcment incomplte. De nouvelles proprits sont susceptibles dapparatre dans les nouvelles versions dUnicode, et vous pouvez mme dfinir vos propres proprits. Nous verrons cela plus loin. Le Consortium Unicode produit les informations que lon retrouve dans les nombreux fichiers que Perl utilise dans son implmentation dUnicode. Pour plus dinformations sur ces fichiers, voyez le chapitre 15. Vous pouvez lire un bon rsum de ce quest Unicode dans le document PATH_TO_PERLLIB/unicode/Unicode3.html o PATH_TO_PERLLIB est ce qui est affich par :
perl -MConfig -le print $Config{privlib}

La plupart des proprits Unicode sont de la forme \p{IsPROP}. Le Is est facultatif, mais vous pouvez le laisser pour des raisons de lisibilit.

customer_8566

Classes de caractres

151

Proprits Unicode de Perl


Le tableau 5-9 donne la liste des proprits composites de Perl. Elles sont dfinies de faon tre raisonnablement proches des dfinitions POSIX standard pour les classes de caractres. Tableau 5-9. Proprits Unicode composites
Proprt IsASCII IsAlnum IsAlpha IsCntrl IsDigit IsGraph IsLower IsPrint IsPunct IsSpace IsUpper IsWord IsXDigit quivalent [\x00-\x7f] [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}] [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}] \p{IsC} \p{Nd} [^\pC\p{IsSpace}] \p{IsLl} \P{IsC} \p{IsP} [\t\n\f\r\p{IsZ}] [\p{IsLu}\p{IsLt}] [_\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}] [0-9a-fA-F]

Perl fournit galement les composites suivants pour chacune des principales catgories des proprits Unicode standard (voir la section suivante) :
Proprit IsC IsL IsM IsN IsP IsS IsZ Signification Codes de contrle et quivalents Lettres Marqueurs Nombres Ponctuation Symboles Sparateurs (Zparateurs?) Normative Oui Partiellement Oui Oui Non Non Oui

Proprits Unicode standard


Le tableau 5-10 donne la liste des proprits Unicode standard les plus basiques, qui drivent de la catgorie de chaque caractre. Aucun caractre nest membre de plus dune catgorie. Certaines proprits sont normatives ; dautres sont simplement informatives. Reportez-vous au standard Unicode pour savoir combien linformation normative est normative, et combien linformation informative ne lest pas.

customer_8566

152
Tableau 5-10. Proprits Unicode standard
Proprit IsCc IsCf IsCn IsCo IsCs IsLl IsLm IsLo IsLt IsLu IsMc IsMe IsMn IsNd IsNl IsNo IsPc IsPd IsPe IsPf IsPi IsPo IsPs IsSc IsSk IsSm IsSo IsZl IsZp IsZs Signification Autre, contrle Autre, format Autre, non affect Autre, usage priv Autre, substitut Lettre, minuscule Lettre, modificateur Lettre, autre Lettre, casse de titre Lettre, majuscule Marque, combinante Marque, entourant Marque, non-espacement Nombre, chiffre dcimal Nombre, lettre Nombre, autre Ponctuation, connecteur Ponctuation, tiret Ponctuation, fermeture Ponctuation, guillemet fermant Ponctuation, guillemet ouvrant Ponctuation, autre Ponctuation, ouvert Symbole, monnaie Symbole, modificateur Symbole, math Symbole, autre Sparateur, de ligne Sparateur, de paragraphe Sparateur, espace

Chapitre 5 Recherche de motif

Normative Oui Oui Oui Oui Oui Oui Non Non Oui Oui Oui Oui Oui Oui Oui Oui Non Non Non Non Non Non Non Non Non Non Non Oui Oui Oui

Un autre ensemble de proprits utiles est li au fait quun caractre peut tre dcompos (de faon canonique ou compatible) en dautres caractres plus simples. La dcomposition canonique ne perd aucune information de formatage. La dcomposition compatible peut perdre des informations de formatage, comme le fait de savoir si le caractre est en exposant.

customer_8566

Classes de caractres
Proprit IsDecoCanon IsDecoCompat IsDCcircle IsDCfinal IsDCfont IsDCfraction IsDCinitial IsDCisolated IsDCmedial IsDCnarrow IsDCnoBreak IsDCsmall IsDCsquare IsDCsub IsDCsuper IsDCvertical IsDCwide IsDCcompat Information perdue Rien Quelque chose (parmi les suivants) Cercle autour du caractre Prfrence de position finale (Arabe) Prfrence de variante de fonte Caractristique de fraction ordinaire Prfrence de position initiale (Arabe) Prfrence de position isole (Arabe) Prfrence de position mdiane (Arabe) Caractristique dtroitesse Prfrence de non-coupure sur un espace ou un tiret Caractristique de petite taille Carr autour dun caractre CJK Position dindice Position dexposant Rotation (dhorizontal vertical) Caractristique de largeur Identit (variable)

153

Voici quelques proprits qui intressent les personnes faisant du rendu bidirectionnel :
Proprit IsBidiL IsBidiLRE IsBidiLRO IsBidiR IsBidiAL IsBidiRLE IsBidiRLO IsBidiPDF IsBidiEN IsBidiES IsBidiET IsBidiAN IsBidiCS IsBidiNSM IsBidiBN IsBidiB Signification Gauche droite (Arabe, Hbreu) Inclusion de gauche droite Force de gauche droite Droite gauche Droite gauche arabe Inclusion de droite-gauche Force de droite gauche Dpile le format directionnel Nombre europen Sparateur de nombre europen Terminateur de nombre europen Nombre arabe Sparateur de nombres communs Marque de non-espacement Limite neutre Sparateur de paragraphe

customer_8566

154
Proprit IsBidiS IsBidiWS IsBidiON IsMirrored Signification Sparateur de segment Blanc Autres neutres

Chapitre 5 Recherche de motif

Image miroir quand utilis de droite gauche

Les proprits suivantes classent diffrents syllabaires selon les sonorits des voyelles :
IsSylA IsSylAA IsSylAAI IsSylAI IsSylC IsSylE IsSylEE IsSylI IsSylII IsSylN IsSylO IsSylOO IsSylU IsSylV IsSylWA IsSylWAA IsSylWC IsSylWE IsSylWEE IsSylWI IsSylWII IsSylWO IsSylWOO IsSylWU IsSylWV

Par exemple, \p{IsSylA} correspondrait \N{KATAKANA LETTER KA} mais pas \N{KATAKANA LETTER KU}. Maintenant que nous vous avons parl de toutes ces proprits Unicode 3.0, nous devons tout de mme lister quelques unes des plus sotriques qui ne sont pas implmentes dans Perl 5.6.0, car cette implmentation tait base en partie sur Unicode 2.0, et que des choses comme lalgorithme bidirectionnel taient encore sur le mtier. Cependant, comme dici ce que vous lisiez ceci, les proprits manquantes pourraient bien avoir t implmentes, nous les avons listes quand mme.

Proprits de bloc Unicode


Certaines proprits Unicode sont de la forme \p{InSCRIPT}. (Remarquez la distinction entre Is et In.) Les proprits In servent tester lappartenance des blocs dun SCRIPT unique. Si vous avez un caractre et que vous vous demandez sil est crit en criture hbraque, vous pouvez le tester avec :
print "Pour moi cest de lHbreu!\n" if chr(1488) =~ /\p{InHebrew}/;

Cela fonctionne en vrifiant si un caractre est dans lintervalle valide de ce type dcriture. Cela peut tre invers avec \P{InSCRIPT} pour savoir si quelque chose nest pas dans un bloc de script particulier, comme \P{InDingbats} pour savoir si une chane contient un caractre non dingbat. Dans les proprits de bloc on trouve les lments suivants :
InArabic InArmenian InArrows InBasicLatin InBengali InBopomofo InBoxDrawing InCherokee InCyrillic InDevanagari InDingbats InEthiopic InGeorgian InGreek InGujarati InGurmukhi InHangulJamo InHebrew InHiragana InKanbun InKannada InKatakana InKhmer InLao InMalayalam InMongolian InMyanmar InOgham InOriya InRunic InSinhala InSpecials InSyriac InTamil InTelugu InThaana InThai InTibetan InYiRadicals InYiSyllables

Sans oublier les impressionnants :


InAlphabeticPresentationForms InArabicPresentationForms-A InArabicPresentationForms-B InHalfwidthandFullwidthForms InHangulCompatibilityJamo InHangulSyllables

customer_8566

Classes de caractres
InBlockElements InBopomofoExtended InBraillePatterns InCJKCompatibility InCJKCompatibilityForms InCJKCompatibilityIdeographs InCJKRadicalsSupplement InCJKSymbolsandPunctuation InCJKUnifiedIdeographs InCJKUnifiedIdeographsExtensionA InCombiningDiacriticalMarks InCombiningHalfMarks InCombiningMarksforSymbols InControlPictures InCurrencySymbols InEnclosedAlphanumerics InEnclosedCJKLettersandMonths InGeneralPunctuation InGeometricShapes InGreekExtended

155
InHighPrivateUseSurrogates InHighSurrogates InIdeographicDescriptionCharacters InIPAExtensions InKangxiRadicals InLatin-1Supplement InLatinExtended-A InLatinExtended-B InLatinExtendedAdditional InLetterlikeSymbols InLowSurrogates InMathematicalOperators InMiscellaneousSymbols InMiscellaneousTechnical InNumberForms InOpticalCharacterRecognition InPrivateUse InSuperscriptsandSubscripts InSmallFormVariants InSpacingModifierLetters

Et le mot le plus long :


InUnifiedCanadianAboriginalSyllabics

Pas mieux. Consultez PATH_TO_PERLLIB/unicode/In/*.pl pour obtenir une liste jour de toutes ces proprits de blocs de caractres. Remarquez que les proprits In ne font que vrifier si le caractre est dans lintervalle allou pour ce script. Rien ne vous garantit que tous les caractres dans cet intervalle sont dfinis ; vous devrez galement tester lune des proprits Is discutes prcdemment pour vrifier si le caractre est dfini. Rien ne vous garantit non plus quune langue particulire nutilise pas des caractres en dehors de lintervalle qui lui est affect. En particulier, de nombreuses langues europennes mlangent les caractres latins tendus avec des caractres Latin-1. Mais bon, si vous avez besoin dune proprit particulire qui nest pas fournie, ce nest pas un gros problme. Continuez lire.

Dfinir vos propres proprits de caractres


Pour dfinir vos propres proprits, vous devrez crire un sous-programme portant le nom de la proprit que vous voulez (voir chapitre 6, Sous-programmes). Le sous-programme doit tre dfini dans le paquetage qui a besoin de la proprit, ce qui signifie que si vous dsirez lutiliser dans plusieurs paquetages, vous devrez soit limporter dun autre module (voir chapitre 11, Modules), ou lhriter comme mthode de classe depuis le paquetage dans lequel il est dfini (voir chapitre 12, Objets). Une fois que cela est fait, le sous-programme doit renvoyer des donnes dans le mme format que les fichiers du rpertoire PATH_TO_PERLLIB/unicode/Is. Cest--dire que vous devez juste retourner une liste de caractres ou des intervalles de caractres en hexadcimal, un par ligne. Sil y a un intervalle, les deux nombres sont spars par une tabulation. Supposons que vous vouliez crer une proprit qui serait vraie si votre caractre

customer_8566

156

Chapitre 5 Recherche de motif

est dans lintervalle de lun des deux syllabaires japonais, nomms hiragana et katakana. (Ensemble on les appelle simplement kana.) Vous pouvez juste mettre les deux intervalles comme suit :
sub InKana { return <<END; 3040 309F 30A0 30FF END }

Vous pourriez galement le dfinir laide de noms de proprits existantes :


sub InKana { return <<END; +utf8::InHiragana +utf8::InKatakana END }

Vous pouvez aussi faire une soustraction en utilisant un prfixe - . Supposons que vous ne vouliez que les vritables caractres, et pas seulement les blocs de caractres. Vous pouvez retirer tous les caractres indfinis comme ceci :
sub IsKana { return <<END; +utf8::InHiragana +utf8::InKatakana -utf8::IsCn END }

Vous pouvez aussi dmarrer avec le complment dun ensemble de caractres en utilisant le prfixe ! :
sub IsNotKana { return <<END; !utf8::InHiragana -utf8::InKatakana +utf8::IsCn END }

Perl lui-mme utilise les mmes trucs pour dfinir la signification de ses propres classes de caractres classiques (comme \w) quand vous les incluez dans vos classes de caractres personnalises (comme [-.\w\s]). Vous pourriez penser que plus les rgles deviennent compliques, plus lentement cela tournera ; mais en fait, une fois que Perl a calcul le motif de bits pour le bloc de 64 bits de votre proprit, il le mmorise pour navoir jamais le recalculer. (Cela est fait dans des blocs de 64 bits pour ne mme pas avoir dcoder votre utf8 pour faire les recherches.) Ainsi, toutes les classes de caractres, internes ou personnalises, tournent toutes peu prs la mme vitesse (rapide) une fois mises en route.

customer_8566

Classes de caractres

157

Classes de caractres de style POSIX


Contrairement aux autres raccourcis de classes de caractres, la notation de style POSIX, [:CLASSE:], nest utilisable que pour la construction dautres classes de caractres, cest-dire lintrieur dune autre paire de crochets. Par exemple, /[.,[:alpha:][:digit:]]/ va chercher un caractre qui est soit un point (littral, car dans une classe de caractres), une virgule, ou un caractre alphabtique ou un nombre. Les classes POSIX disponibles partir de la version 5.6 de Perl sont listes dans le tableau 5-11. Tableau 5-11. Classes de caractres POSIX
Classe alnum alpha ascii cntrl Signification Tout alphanumrique, cest--dire un alpha ou un digit. Toute lettre. (Cela fait beaucoup plus de lettres que vous pensez, sauf si vous pensez en Unicode, auquel cas cela fait quand mme beaucoup.) Tout caractre avec une valeur numrique comprise entre 0 et 127. Tout caractre de contrle. En gnral ce sont des caractres qui ne produisent pas daffichage par eux-mmes, mais contrlent le terminal dune faon ou dune autre. Par exemple, les caractres de nouvelle ligne, de fin de page ou despace arrire sont des caractres de contrle. Les caractres ayant une valeur numrique infrieure 32 sont le plus souvent considrs comme des caractres de contrle. Un caractre reprsentant un chiffre dcimal, comme ceux entre 0 et 9. (Cela comprend dautres caractres en Unicode.) quivalent \d. Tout caractre alphanumrique ou de ponctuation. Une lettre minuscule. Tout caractre alphanumrique, de ponctuation ou despacement. Tout caractre de ponctuation. Tout caractre despacement. Cela inclut tabulation, nouvelle ligne, saut de page et retour chariot (et encore beaucoup plus en Unicode). quivalent \s. Tout caractre en majuscule (ou casse de titre). Tout caractre didentificateur, soit un alnum ou un soulign. Tout chiffre hexadcimal. Bien que cela semble un peu bte ([0-9a-fA-F] marche trs bien), cest inclus pour tre complet.

digit graph lower print punct space

upper word xdigit

Vous pouvez inverser la classe de caractres POSIX en prfixant le nom de la classe par un ^ aprs le [:. (Cest une extension apporte par Perl.) Par exemple :
POSIX [:^digit:] [:^space:] [:^word:] Classique \D \S \W

customer_8566

158

Chapitre 5 Recherche de motif

Si le pragma use utf8 nest pas demand, mais que le pragma use locale lest, la classe correspond directement avec les fonctions quivalentes de linterface isalpha(3) de la librairie C (except word, qui est une extension Perl correspondant \w). Si le pragma utf8 est utilis, les classes de caractres POSIX sont exactement quivalentes aux proprits Is listes dans le tableau 5-9. Par exemple, [:lower:] et \p{Lower} sont quivalentes, sauf que les classes POSIX ne peuvent tre utilises que dans les classes de caractres construites, tandis que les proprits Unicode ne sont pas soumises de telles restrictions et peuvent tre utilises dans des motifs partout o les raccourcis Perl comme \s et \w peuvent ltre. Les crochets font partie de la construction de style POSIX [::] et pas de la classe de caractres. Ce qui nous amne crire des motifs tels que /^[[:lower:][:digit:]]+$/ pour correspondre une chane consistant entirement de lettres minuscules ou de chiffres (avec un saut de ligne final facultatif). En particulier, ceci ne fonctionne pas :
42 =~ /^[:digit:]+$/ # FAUX

Cela est d au fait quon nest pas dans une classe de caractres. Ou plutt, cest une classe de caractres, celle qui reprsente les caractres : , i , t , g et d . Perl se moque du fait que vous ayez utilis deux : (et deux i ). Voici ce dont vous avez en fait besoin :
42 =~ /^[[:digit:]]+$/

Les classes de caractres POSIX [.cc.] et [=cc=] sont reconnues, mais produisent une erreur indiquant quelles ne sont pas utilisables. Lutilisation de nimporte quelle classe de caractres POSIX dans une version de Perl plus ancienne ne marchera pas, et de faon probablement silencieuse. Si vous comptez utiliser les classes de caractres POSIX, il est prfrable dimposer lutilisation dune nouvelle version de Perl en crivant :
use 5.6.0;

Quantificateurs
moins que vous nen dcidiez autrement, chaque lment dune expression rgulire ne correspond quune fois quelque chose. Avec un motif comme /nop/, chacun de ces caractres doit correspondre, lun la suite de lautre. Les mots comme panoplie ou xnophobie marchent bien, car o la correspondance se fait na aucune importance. Si vous vouliez trouver la fois xnophobie et Snoopy , vous ne pourriez pas utiliser le motif /nop/, puisque cela requiert quil ny ait quun seul o entre le n et le p , et que Snoopy en a deux. Cest ici que les quantificateurs montrent leur utilit : ils indiquent combien de fois quelque chose peut correspondre, au lieu de une fois par dfaut. Les quantificateurs dans une expression rgulire sont comme les boucles dans un programme ; en fait, si vous regardez une expression rgulire comme un programme, alors ce sont des boucles. Certaines boucles sont exactes, comme rpte cette correspondance cinq fois seulement ({5}). Dautres vous donnent la fois la limite infrieure et la limite suprieure du nombre de correspondances, comme rpte ceci au moins deux fois, mais pas plus de quatre ({2,4}). Dautres nont pas de limite suprieure du tout, comme trouve ceci au moins deux fois, mais ensuite autant de fois que tu veux ({2,}).

customer_8566

Quantificateurs
Le tableau 5-12 liste les quantificateurs que Perl reconnat dans un motif. Tableau 5-12. Comparaison des quantificateurs de motifs
Maximum {MIN,MAX} {MIN,} {COMPTE} * + ? Minimum {MIN,MAX}? {MIN,}? {COMPTE}? *? +? ?? Plage autorise

159

Doit apparatre au moins MIN fois mais pas plus de MAX fois Doit apparatre au moins MIN fois Doit apparatre exactement COMPTE fois 0 ou plus (comme {0,}) 1 fois ou plus (comme {1,}) 0 ou 1 fois (comme {0,1})

Quelque chose suivi dune * ou dun ? nest pas oblig de correspondre tout prix. Cest parce que cela peut correspondre 0 fois et toujours tre considr comme un succs. Un + est souvent un meilleur choix, car llment recherch doit tre prsent au moins une fois. Ne vous laissez pas embrouiller par lemploi de exactement dans le tableau prcdent. Il ne fait rfrence quau nombre de rptitions, et pas la chane complte. Par exemple, $n =~ /\d{3}/ ne dit pas est-ce que cette chane fait exactement trois chiffres de long ? . En fait le motif se proccupe de savoir sil existe une position dans $n laquelle trois chiffres apparaissent les uns la suite des autres. Des chanes comme 101 rue de la Rpublique correspondent, tout comme des chanes telles que 75019 ou 0 825 827 829 . Toutes contiennent trois chiffres la suite un ou plusieurs endroits, ce qui est tout ce que vous demandiez. Voir dans la section Positions lutilisation des assertions de position (comme dans /^\d{3}$/) pour prciser votre recherche. Si on leur donne la possibilit de correspondre un nombre variable de fois, les quantificateurs maximaux vont essayer de maximiser le nombre de rptitions. Cest pourquoi quand nous disons autant de fois que tu veux , les quantificateurs gourmands le comprennent comme le plus de fois que tu le peux , la seule condition que cela nempche pas des spcifications plus loin dans lexpression de correspondre. Si un motif contient deux quantificateurs ouverts, les deux ne peuvent videmment pas consommer lintgralit de la chane : les caractres utiliss par la premire partie de lexpression ne sont plus disponibles pour la partie qui suit. Chaque quantificateur est gourmand aux dpens de ceux qui le suivent, en lisant le motif de gauche droite. Cest du moins le comportement traditionnel des quantificateurs dans les expressions rgulires. Cependant Perl vous permet de modifier le comportement de ses quantificateurs : en mettant un ?aprs un quantificateur, vous le transformez de maximal en minimal. Cela ne signifie pas quun quantificateur minimal va toujours correspondre au nombre minimum de rptitions permises par ses spcifications, pas plus quun quantificateur maximal correspond toujours au plus grand nombre dfini dans ses spcifications. La correspondance globale doit toujours se faire, et le quantificateur minimal prendra juste ce quil faut pour que ce soit un succs, et pas plus. (Les quantificateurs minimaux prfrent la satisfaction la gourmandise.) Par exemple dans la correspondance :
"exigence" =~ /e(.*)e/ # $1 vaut maintenant "xigenc"

customer_8566

160

Chapitre 5 Recherche de motif

le .* correspond xigenc , la plus longue chane possible laquelle il peut correspondre. (Il stocke galement cette valeur dans $1, comme cela est expliqu dans la section Capture et regroupement plus loin dans ce chapitre.) Bien quune correspondance plus courte fut possible, un quantificateur gourmand sen moque. Sil a le choix entre deux possibilits partir de la mme position, il retournera toujours la plus longue des deux. Comparez ceci avec cela :
"exigence" =~ /e(.*?)e/ # $1 vaut maintenant "xig"

Ici, cest la version minimale, .*?, qui est utilise. Lajout du ? l* fait que *? a un comportement oppos : ayant le choix entre deux possibilits partir du mme point, il prend toujours la plus courte des deux. Bien que vous puissiez lire *? comme une injonction correspondre zro ou plus de quelque chose en prfrant zro, cela ne veut pas dire quil correspondra toujours zro caractre. Si ctait le cas ici, par exemple, et quil laissait $1 la valeur "", alors le second e ne serait pas trouv, puisquil ne suit pas immdiatement le premier. Vous pourriez aussi vous demander pourquoi, alors quil cherchait une correspondance minimale avec /e(.*?)e/, Perl na pas plutt mis nc dans $1. Aprs tout, nc se trouve lui aussi entre deux e et est plus court que xig . En Perl, le choix minimal/maximal se fait seulement lorsquon recherche la plus courte ou la plus longue parmi plusieurs correspondances ayant toutes le mme point de dpart. Si plusieurs correspondances possibles existent, mais commencent des endroits diffrents dans la chane, alors leurs longueurs nont aucune importance pas plus que le fait que vous ayez utilis un quantificateur minimal ou maximal. La premire de plusieurs correspondances possibles est toujours prpondrante devant celles qui la suivent. Cest seulement lorsque plusieurs correspondances possibles dmarrent du mme point dans la chane que le ct minimal ou maximal de la correspondance sert les dpartager. Si les points de dpart sont diffrents, il ny a rien dpartager. Les correspondances de Perl sont normalement de type la plus gauche la plus longue ; avec une correspondance minimale, cela devient la plus gauche la plus courte. Mais la partie la plus gauche ne change pas et reste le critre dominant.8 Il y a deux manires de passer lorientation gauche du dtecteur de motif. Premirement vous pouvez utiliser un quantificateur gourmand au dbut (typiquement .*) pour essayer de consommer le dbut de la chane. En cherchant la correspondance pour un quantificateur gourmand, il essaie dabord la correspondance la plus longue ce qui provoque effectivement une recherche de droite gauche dans le reste de la chane :
"exigence" =~ /.*e(.*?)e/ # $1 vaut maintenant "nc"

Mais faites attention avec cette mthode, car la correspondance complte contient maintenant toute la chane jusqu ce point.

8. Tous les moteurs de regex ne fonctionnent pas comme cela. Certains croient plutt en la gourmandise globale, o la correspondance la plus longue gagne toujours, mme si elle apparat plus tard dans la chane. Perl ne fonctionne pas comme cela. Vous pourriez dire que lardeur prime sur la gourmandise (ou le rationnement). Pour une discussion plus formelle de ce principe et de beaucoup dautres, voir la section Le petit Moteur qui /(ne )?pouvait( pas)?/ .

customer_8566

Positions

161

La seconde manire de dfaire cette inclination gauche est dutiliser les assertions de position, qui sont discutes dans la section suivante.

Positions
Certaines constructions de regex reprsentent des positions dans la chane traiter, qui est juste un emplacement gauche ou droite dun vritable caractre. Ces mtasymboles sont des exemples dassertions de largeur nulle. Nous les appellerons souvent simplement assertions . (On les connait aussi sous le nom d ancres , car elles lient une partie du motif une position particulire.) Vous pouvez toujours manipuler les positions dans une chane sans utiliser de motif. La fonction intgre substr vous permet dextraire et daffecter des sous-chanes, calcules partir du dbut de la chane, de la fin de la chane ou partir dune position numrique particulire. Cest juste ce dont vous avez besoin si vous travaillez avec des enregistrements de longueur fixe. Les motifs deviennent ncessaires quand un dcalage numrique nest plus suffisant. Et la plupart du temps, les dcalages ne sont pas suffisants disons pas suffisament commodes, par rapport aux motifs.

Les dbuts : assertions \A et ^


Lassertion \A correspond seulement au dbut de la chane, quelles que soient les circonstances. Cependant lassertion ^ est lassertion traditionnelle de dbut de ligne, ainsi que celle de dbut de chane. Cest pourquoi si le motif utilise le modificateur /m9 et que la chane contient des sauts de ligne, ^ correspond galement nimporte o dans la chane immdiatement aprs un caractre de saut de ligne :
/\Abar/ /^bar/ /^bar/m # Correspond "bar" et "barbecue" # Correspond "bar" et "barbecue" # Correspond "bar" et "barbecue" et "zinc\nbar"

Utilise en mme temps que /g, le modificateur /m permet ^ de correspondre plusieurs fois dans la mme chane :
s/^\s+//gm; $total++ while /^./mg; # Supprime les blancs en tte de chaque ligne # Compte les lignes qui ne sont pas vides

Fins : assertions \z, \Z et $


Le mtasymbole \z correspond la fin de la chane, quoi quil y ait lintrieur. \Z correspond juste avant le saut de ligne en fin de chane sil y en a un, ou la fin sil ny en a pas. Le mtacaractre $ signifie en gnral la mme chose que \Z. Cependant, si le modificateur /m a t spcifi et que la chane contient des sauts de ligne, alors $ peut aussi correspondre nimporte o dans la chane, juste avant un saut de ligne :
/bot\z/ /bot\Z/ # Correspond avec "robot" # Correspond avec "robot" et "poulbot\n"

9. Ou si vous avez mis la variable obsolte $* 1 et que vous nignorez pas $* avec le modificateur /s.

customer_8566

162
/bot$/ /bot$/m

Chapitre 5 Recherche de motif


# Correspond avec "robot" et "poulbot\n" # Correspond avec "robot" et "poulbot\n" et "robot\nmnager" et "robot\n" et "robot\n" et "ce\nrobot\n" et "robot\n" uniquement -- mais pourquoi ne

/^robot$/ # Correspond avec "robot" /^robot$/m # Correspond avec "robot" /\Arobot\Z/ # Correspond avec "robot" /\Arobot\z/ # Correspond avec "robot" #pas avoir utilis eq ?

Tout comme avec ^, le modificateur /mpermet $ de correspondre plusieurs fois dans la mme chane quand il est utilis avec /g. (Ces exemples supposent que vous avez lu un enregistrement multiligne dans $_, par exemple en mettant $/ "" avant la lecture.)
s/\s*$//gm; # Supprime les blancs en fin de chaque ligne du paragraphe

while (/^([^:]+):\s*(.*)/gm ) { # obtient les en-ttes de mail $headers{$1} = $2; }

Plus loin dans ce chapitre, la section Interpolation de variables, nous discuterons de la faon dont vous pouvez interpoler des variables dans des motifs : si $toto vaut bc , alors /a$toto/ est quivalent /abc/. Ici, le $ ne correspond pas la fin de la chane. Pour quun $ corresponde la fin de la chane, il doit tre la fin du motif ou tre immdiatement suivi dune barre verticale ou dune parenthse fermante.

Limites : assertions \b et \B
Lassertion \b correspond toute limite de mot, celle-ci tant dfinie comme la position entre un caractre \w et un caractre \W, dans nimporte quel ordre. Si lordre est \W\w cest la limite en dbut de mot, et si lordre est \w\W cest la limite en fin de mot. (Une extrmit de chane compte comme un caractre \W ici.) Lassertion \B correspond toute position qui nest pas une limite de mot, cest--dire au milieu de \w\w ou de \W\W.
/\best\b/ /\Best\B/ /\best\B/ /\Best\b/ # # # # correspond correspond correspond correspond "ce quil est" et " lest dEden" "zeste" et "intestin" "estival" et "il testime" et "ouest puis nord" "al

Comme \W comprend tous les caractres de ponctuation, (sauf le soulign), il y a des limites \b au milieu de chanes comme aujourdhui , booktech@oreilly.com , S.N.C.F. et cl/valeur . lintrieur dune classe de caractres ([\b]), un \b reprsente un caractre espace arrire plutt quune limite de mot.

Reconnaissance progressive
Utilise avec le modificateur /g, la fonction pos vous permet de connatre ou de modifier la position partir de laquelle la prochaine comparaison progressive commencera :
$voleur = "Bilbon Baggins"; while ($voleur =~ /b/gi) { printf "Trouv un B en %d\n", pos($voleur)-1; }

customer_8566

Positions

163

(Nous retirons un de la position car cest la longueur de la chane que nous voulions, alors que pos renvoie toujours la position juste aprs la fin de la reconnaissance prcdente.) Le code ci-dessus affiche :
Trouv un B en 0 Trouv un B en 3 Trouv un B en 7

Aprs un chec, la position de reconnaissance est normalement remise zro. Si vous utilisez le modificateur /c (pour continue ), alors quand le /g se termine, lchec de la reconnaissance ne rinitialise pas le pointeur de position. Cela vous permet de continuer votre recherche au-del de ce point, sans recommencer partir du dbut.
$voleur = "Bilbon Baggins"; while ($voleur =~ /b/gci) { # AJOUT DE /c printf "Trouv un B en %d\n", pos($voleur)-1; } while ($voleur =~ /i/gi) { printf "Trouv un I en %d\n", pos($voleur)-1; }

En plus des trois B trouvs prcdemment, Perl indique maintenant quil a trouv un i la position 11. Sans le /c, la seconde boucle de reconnaissance aurait recommenc depuis le dbut de la chane et dabord trouv un autre i la position 1.

L o vous en tiez : assertion \G


Ds que vous commencez rf lchir en termes de la fonction pos, il est tentant de commencer creuser dans votre chane coups de substr, mais cest rarement la bonne chose faire. La plupart du temps, si vous avez commenc avec une recherche de motif, vous devriez continuer avec une recherche de motif. Cependant, si vous recherchez une assertion de position, cest probablement \G quil vous faut. Lassertion \G reprsente lintrieur du motif le mme point que pos reprsente lextrieur. Quand vous faites une recherche progressive avec le modificateur /g (ou que vous avez utilis la fonction pos pour slectionner directement le point de dpart), vous pouvez utiliser \G pour spcifier la position qui suit la fin de la reconnaissance prcdente. Cest--dire quil reconnat la position immdiatement avant le caractre qui serait identifi par pos. Cela vous permet de vous souvenir o vous en tiez :
($recette = <<DISH) =~ s/^\s+//gm; # Anchois sauce Roswel Prchauffer le four 451 deg. fahrenheit. Mlanger 1 ml. de dilithium avec 3 oz. de NaCl et y plonger 4 anchois. Glacer avec 1 gr. de mercure. Faire cuire 4 heures et laisser refroidir 3 secondes. Pour 10 martiens. DISH $recette =~ /\d+ /g; $recette =~ /\G(\w+)/;

# $1 vaut "deg"

customer_8566

164
$recette $recette $recette $recette =~ =~ =~ =~ /\d+ /g; /\G(\w+)/; /\d+ /g; /\G(\w+)/;

Chapitre 5 Recherche de motif

# $1 vaut "ml" # $1 vaut "gr"

Le mtasymbole \G est souvent utilis dans une boucle, comme nous allons le monrer dans notre prochain exemple. Nous faisons une pause aprs chaque suite de chiffres, et cette position, nous testons sil y a une abrviation. Si oui, nous rcuprons les deux mots qui suivent. Sinon, nous rcuprons seulement le mot suivant :
pos($recette) = 0; # Par scurit, initialise \G 0 while ( $recette =~ /(\d+) /g ) { my $quantite = $1; if ($recette =~ / \G (\w{0,3}) \. \s+ de \s+ (\w+) /x) { # abrv. + mot print "$quantite $1 de $2\n"; } else { $recette =~ / \G (\w+) /x; # juste un mot print "$quantite $1\n"; } }

Ce qui donne :
451 deg 1 ml de dilithium 3 oz de NaCl 4 anchois 1 gr de mercure 4 heures 3 secondes 10 martiens

Capture et regroupement
Les motifs vous permettent de regrouper des portions de votre motif dans des sous-motifs et de vous souvenir des chanes reconnues par ces sous-motifs. Nous appellerons le premier comportement regroupement et le second capture.

Capture
Pour capturer une sous-chane pour une utilisation ultrieure, mettez des parenthses autour du motif qui la reconnat. La premire paire de parenthses stocke sa sous-chane dans $1, la deuxime paire dans $2 et ainsi de suite. Vous pouvez utilisez autant de parenthses que vous voulez ; Perl continuera dfinir des variables numrotes pour que vous puissiez reprsenter ces chanes captures. Quelques exemples :
/(\d)(\d)/ # Trouve deux chiffres, qui sont capturs dans $1 et $2 /(\d+)/ # Trouve un ou plusieurs chiffres, capturs ensemble dans $1 /(\d)+/ # Trouve un chiffre une fois ou plus, et capture le dernier dans $1

Remarquez la diffrence entre le deuxime et le troisime motifs. La deuxime forme

customer_8566

Capture et regroupement

165

est en gnral ce que vous voulez. La troisime forme ne cre pas plusieurs variables pour plusieurs chiffres. Les parenthses sont numrotes quand le motif est compil, pas quand il est utilis. Les chanes captures sont souvent appeles rfrences arrires car elles font rfrence des parties du texte situes en arrire par rapport la position courante. Il existe en fait deux manires dutiliser ces rfrences arrires. Les variables numrotes que vous avez vues donnent accs en dehors du motif aux rfrences arrires, mais lintrieur du motif, cela ne marche pas. Vous devez utiliser \1, \2, etc.10 Pour trouver les mots doubls comme le le ou est est , vous pourriez utilisez ce motif :
/\b(\w+) \1\b/i

Mais la plupart du temps, vous utiliserez la forme $1, car en gnral on applique un motif, pour ensuite faire quelque chose des sous-chanes. Supposons que vous ayez du texte (des en-ttes de mail) qui ressemble a :
From: gnat@perl.com To: camelot@oreilly.com Date: Mon, 17 Jul 2000 09:00:00 -1000 Subject: Eye of the needle

et que vous vouliez construire un hachage qui fasse le lien entre le texte avant les deuxpoints et celui aprs. Si vous boucliez sur ce texte ligne ligne (par exemple parce que vous lisez un fichier), vous pourriez faire comme suit :
while (<>) { /^(.*?): (.*)$/; $champs{$1} = $2; } # Texte avant les deux-points dans $1, aprs dans $2

Comme $`, $& et $, ces variables numrotes sont porte dynamique jusqu la fin du bloc ou de la chane eval englobant, ou jusqu la prochaine recherche de motif russie, selon lequel se produit le premier. Vous pouvez galement les utiliser dans la partie droite (la zone de remplacement) dune substitution :
s/^(\S+) (\S+)/$2 $1/; # Intervertit les deux premiers mots

Les regroupements peuvent semboter, et quand ils le font, les groupes sont compts par lordre de leurs parenthses ouvrantes. Donc, si on donne la chane Primula Brandebouc au motif :
/^((\w+) (\w+))$/

il capturerait Primula Brandebouc dans $1, Primula dans $2, et Brandebouc dans $3. Cela est dcrit la figure 5-1.

10. Vous ne pouvez pas utiliser $1 pour une rfrence arrire lintrieur dun motif, car il aurait dj t interpol au moment o la regex a t compile. Cest pourquoi nous utilisons la notation traditionnelle \1 pour les rfrences arrires lintrieur dun motif. Pour les rfrences deux ou trois chiffres, il y a une ambigut avec la notation octale des caractres, mais cest finement rsolu en regardant combien de motifs capturs sont disponibles. Par exemple, si Perl voit un mtasymbole \11, cest quivalent $11 seulement sil y a au moins 11 sous-chanes capturs plus tt dans le motif. Sinon cest quivalent \011, cest--dire un caractre de tabulation.

customer_8566

166

Chapitre 5 Recherche de motif

Figure 5-1. Cration de rfrences arrires avec des parenthses Les motifs avec capture sont souvent utiliss en contexte de liste pour remplir une liste de valeurs, car le motif est assez malin pour retourner les sous-chanes comme une liste :
($premier, $dernier) = /^(\w+) (\w+)$/; ($tout, $premier, $dernier) = /^((\w+) (\w+))$/;

Avec le modificateur /g, un motif peut renvoyer plusieurs sous-chanes issues de plusieurs correspondances, le tout dans une seule liste. Supposons que vous ayez len-tte que nous avons vu prcdemment dans une seule chane (disons dans $_). Vous pourriez faire la mme chose que notre boucle ligne ligne avec une seule instruction :
%champs = /^(.*?): (.*)$/gm;

Le motif russit quatre fois, et chaque fois il trouve deux sous-chanes. La recherche /gm retourne lensemble comme une liste plate de huit chanes, que laffectation de liste %champs interprtera comme quatre couples cl/valeur, ramenant ainsi lharmonie dans lunivers. Plusieurs autres variables spciales traitent du texte captur dans des recherches de motif. $& contient la chane trouve dans son ensemble, $` tout ce qui est gauche de la correspondance, $ tout ce qui est droite. $+ garde le contenu de la dernire rfrence arrire.
$_ = "Parlez, <EM>ami</EM>, et entrez."; m[ (<.*?>) (.*?) (</.*?>) ]x; # Une balise, du texte, et une balise de fin print "prematch: $`\n"; # Parlez, print "match: $&\n"; # <EM>ami</EM> print "postmatch: $\n"; # , et entrez. print "lastmatch: $+\n"; # </EM>

Pour plus dexplication sur ces variables elfiques magiques (et pour savoir comment les crire en anglais), voir le chapitre 28, Noms spciaux. Le tableau @- (@LAST_MATCH_START) contient les positions des dbuts de chacunes des correspondances, et @+ (@LAST_MATCH_END) contient les positions de leurs fins :
#!/usr/bin/perl $alphabet = "abcdefghijklmnopqrstuvwxyz"; $alphabet =~ /(hi).*(stu)/; print "La recherche complte a commenc en $-[0] et sest termine en $+[0]\n";

customer_8566

Capture et regroupement
print "La premire recherche a commenc en $-[1] et sest termine en $+[1]\n"; print "La deuxime recherche a commenc en $-[2] et sest termine en $+[2]\n";

167

Si vous voulez trouver une parenthse littrale plutt que de linterprter comme un mtacaractre, antislashez-la :
/\(p.e., .*?\)/

Ceci trouve un exemple entre parenthses (p.e., celui-ci). Mais comme le point est un joker, cela trouve aussi toute phrase entre parenthses dont la premire lettre est un p et la troisime un e (pied, par exemple).

Regroupement
Les parenthses simples regroupent et capturent la fois. Mais parfois vous nen demandez pas tant. Parfois vous voulez juste regrouper des portions du motif sans crer de rfrence arrire. Vous pouvez utiliser une forme tendue de parenthses pour supprimer la capture : la notation (?:PATTERN) va regrouper sans capturer. Il y a au moins trois raisons pour lesquelles vous voudrez regrouper sans capturer : 1. Pour quantifier quelque chose. 2. Pour limiter la porte dune alternative ; par exemple, /^chat|chien|vache$/ aura besoin dtre crit /^(?:chat|chien|vache)$ si vous ne voulez pas que le chat file avec le ^. 3. Pour limiter la porte dun modificateur de motif un sous-motif spcifique, comme dans /toto(?-i:Attention_A_La_Casse)titi/i. (Voir la section suivante, Modificateurs clotrs.) De plus, il est plus efficace de supprimer la capture de quelque chose que vous nallez pas utiliser. En revanche, la notation est un peu moins lisible. Dans un motif, une parenthse ouvrante immdiatement suivie dun point dinterrogation indique une extension de regex. Le bestiaire actuel des expressions rgulires est relativement fix nous nosons pas crer un nouveau mtacaractre, de peur de casser danciens programmes Perl. Au lieu de cela, la syntaxe dextension permet dajouter de nouvelles fonctionnalits au bestiaire. Dans le reste du chapitre, nous allons voir beaucoup dautres extensions de regex, lesquelles feront toutes du regroupement sans capture, avec quelque chose dautre. Lextension (?:MOTIF) est spciale en ce quelle ne fait rien dautre. Donc si vous crivez :
@champs = split(/\b(?:a|b|c)\b/)

cest comme :
@champs = split(/\b(a|b|c)\b/)

sauf que cela ne renvoie pas de champs supplmentaires. (Loprateur split est un peu comme m//g en ce quil retournera des champs supplmentaires pour chaque chane capture dans le motif. Dordinaire, split ne retourne que ce qui na pas t trouv. Pour en savoir plus sur split, voir le chapitre 29.)

customer_8566

168

Chapitre 5 Recherche de motif

Modificateurs clotrs
Vous pouvez clotrer les modificateurs /i, /m, /s et /x dans une portion de votre motif en les insrant (sans le slash) entre le ? et le : de la notation de regroupement. Si vous crivez :
/Harry (?i:s) Truman/

cela correspondra la fois Harry S Truman et Harry s Truman , tandis que :


/Harry (?x: [A-Z] \.? \s )?Truman/

correspondra la fois Harry S Truman et Harry S. Truman , aussi bien qu Harry Truman , et :
/Harry (?ix: [A-Z] \.? \s )?Truman/

trouvera les cinq, en combinant les modificateurs /i et /x dans le clotre. Vous pouvez galement soustraire des modificateurs dun clotre avec un signe moins :
/Harry (?x-i: [A-Z] \.? \s )?Truman/i

Ceci trouve le nom dans toutes les combinaisons de majuscules et minuscules mais si linitiale centrale est fournie, elle doit tre en majuscules, car le /i appliqu au motif dans son ensemble est suspendu lintrieur du clotre. En omettant les deux-points et le MOTIF, vous pouvez exporter les rglages des modificateurs un regroupement extrieur, en le transformant en clotre. Cest--dire que vous pouvez slectivement activer ou dsactiver les modificateurs pour le regroupement qui se trouve un niveau lextrieur des parenthses du modificateur, comme ceci :
/(?i)toto/ /toto((?-i)titi)/i /toto((?x-i) titi)/ # quivalent /toto/i # "titi" doit tre en minuscules # Active /x et dsactive /i pour "titi"

Remarquez que le deuxime et le troisime exemples crent des rfrences arrires. Si ce ntait pas ce que vous vouliez, alors vous auriez d utiliser respectivement (?-i:titi) et (?x-i: titi). Activer les modificateurs sur une partie de votre motif est particulirement utile quand vous voulez que . corresponde des sauts de ligne dans une partie de votre motif, mais pas dans le reste. Activer /s sur tout le motif ne vous sera daucune utilit dans ce cas.

Alternative
lintrieur dun motif ou dun sous-motif, utilisez le mtacaractre | pour spcifier un ensemble de possibilits dont chacune peut correspondre. Par exemple :
/Gandalf|Saroumane|Radagaste/

correspond Gandalf, Saroumane ou Radagaste. Lalternative stend seulement jusquaux parenthses qui lentourent les plus proches (quelles capturent ou non) :
/perc|l|s|tes/ /per(c|l|s|t)es/ /per(?:c|l|s|t)es/ # Trouve perc, l, s ou tes # Trouve perces, perles, perses ou pertes # Trouve perces, perles, perses ou pertes

customer_8566

Alternative

169

La deuxime et la troisime formes correspondent aux mmes chanes, mais la deuxime capture le caractre changeant, tandis que la troisime ne le fait pas. Dans toutes les positions, le Moteur essaie de trouver le premier lment de lalternative, puis le deuxime, et ainsi de suite. La longueur de chaque lment na pas dimportance, ce qui signifie que dans ce motif :
/(Sam|Samsagace)/

$1 ne vaudra jamais Samsagace, quelle que soit la chane sur laquelle on lutilise, car Sam sera toujours trouv en premier. Quand vous avez des recherches qui se superposent comme ceci, mettez les plus longues au dbut. Mais lordre des lments de lalternative na dimportance qu une position donne. La boucle externe du Moteur fait une recherche de gauche droite, cest pourquoi ce qui suit trouve toujours le premier Sam :
"Sam je suis, dit Samsagace" =~ /(Samsagace|Sam)/; # $1 eq "Sam"

Mais vous pouvez forcer une recherche de droite gauche en utilisant les quantificateurs gourmands, comme nous lavons vu prcdemment dans Quantificateurs :
"Sam je suis, dit Samsagace" =~ /.*(Samsagace|Sam)/; # $1 eq "Samsagace"

Vous pouvez dfaire toute recherche gauche droite (ou de droite gauche) en incluant nimporte laquelle des assertions de position vues prcdemment, comme \G, ^ et $. Ici nous ancrons le motif la fin de la chane :
"Sam je suis, dit Samsagace" =~ /(Samsagace|Sam)$/; # $1 eq "Samsagace"

Cet exemple met le $ en facteur en dehors de lalternative (car nous avions dj une paire de parenthses en dehors de laquelle le mettre), mais en labsence de parenthses vous pouvez galement distribuer les assertions sur tout ou partie des lments de lalternative, selon comment vous voulez quils trouvent. Ce petit programme affiche les lignes qui commencent par un token __DATA__ ou __END__ :
#!/usr/bin/perl while (<>) { print if /^__DATA__|^__END__/; }

Mais faites attention avec cela. Souvenez-vous que le premier et le dernier lments de lalternative (avant le premier | et aprs le dernier) ont tendance avaler les autres de chaque ct, sauf sil y a des parenthses autour. Une erreur courante est de demander :
/^chat|chien|vache$/

quand vous voulez en fait :


/^(chat|chien|vache)$/

La premire trouve chat au dbut de la chane, ou chien nimporte o, ou bien vache en fin de chane. La deuxime trouve nimporte quelle chane consistant simplement de chat , chien ou vache . Elle capture galement $1, ce qui nest pas forcment ce que vous voulez. Vous pouvez galement crire :
/^chat$|^chien$|^vache$/

Nous vous montrerons une autre solution plus loin. Un lment de lalternative peut tre vide, auquel cas il russit toujours.

customer_8566

170

Chapitre 5 Recherche de motif

/com(posite|)/; # Trouve "composite" ou "com" /com(posite(s|)|)/; # Trouve "composites", "composite" ou "com"

Cela revient utiliser le quantificateur ?, qui trouve 0 ou 1 fois :


/com(posite)?/; # Trouve "composite" ou "com" /com(posite(s?))?/; # Trouve "composites", "composite" ou "com" /com(posites?)?/; # Pareil, mais nutilise pas $2

Il y a cependant une diffrence. Quand vous appliquez le ? un sous-motif qui fait une capture dans une variable numrote, cette variable sera indfinie sil ny a pas de chane y mettre. Si vous avez mis llment vide dans lalternative, elle serait toujours fausse, mais ce serait en fait une chane vide dfinie.

Garder le contrle
Comme le sait tout bon chef dquipe, cela ne sert rien dtre toujours sur le dos de vos employs. Dites-leur simplement ce que vous voulez, et laissez-les trouver la meilleure manire de le faire. De mme, la meilleure manire de voir une expression rgulire, cest comme une spcification : Voil ce que je veux ; trouve-moi une chane qui correspond . Dun autre ct, les meilleurs chefs dquipe comprennent ce que leurs employs essayent de faire. Cest galement vrai pour les expressions rgulires en Perl. Mieux vous comprenez comment Perl sacquitte de la tche de trouver un motif particulier, plus vous serez capable dutiliser les capacits de recherche de motif de Perl en connaissance de cause. Une des choses les plus importantes comprendre propos de la recherche de motif en Perl, cest quand ne pas lutiliser.

Laisser Perl faire le boulot


Quand certaines personnes apprennent les expressions rgulires, elles sont souvent tentes de voir tout problme comme un problme de recherche de motif. Et quand bien mme ce serait vrai en gnral, la recherche de motif est plus que la simple valuation dexpressions rgulires. Cest aussi comme rechercher vos cls de voiture o vous les avez fait tomber, et pas seulement sous le rverbre, l o vous y voyez le mieux. Dans le monde rel, nous savons tous quil est plus efficace de chercher aux bons endroits quaux mauvais. De mme, vous devriez utiliser le contrle de f lux de Perl pour dcider quels motifs excuter et lesquels ignorer. Une expression rgulire est plutt maligne, mais pas plus quun cheval. Elle peut tre distraite si elle voit trop de choses la fois. Cest pourquoi il vous faut parfois lui mettre des illres. Par exemple, souvenez-vous de notre prcdent exemple dalternative :
/Gandalf|Saroumane|Radagaste/

Cela marche comme prvu, mais pas aussi bien que possible, car elle cherche chaque nom chaque position dans la chane avant de passer la suivante. Les lecteurs attentifs du Seigneur des anneaux se souviendront que, des trois magiciens mentionns ci-dessus, Gandalf est mentionn plus souvent que Saroumane, et que Saroumane est mentionn

customer_8566

Garder le contrle

171

plus souvent que Radagaste. Il est donc en gnral plus efficace dutiliser les oprateurs logiques de Perl pour raliser lalternative :
/Gandalf/ || /Saroumane/ || /Radagaste/

Cest galement une autre manire de passer outre la recherche oriente gauche du Moteur. Il ne recherche Saroumane que si Gandalf est introuvable. Et il ne cherche Radagaste que si Saroumane est galement absent. Non seulement cela change lordre de recherche des diffrents termes, but cela permet galement loptimiseur dexpressions rgulires de mieux fonctionner. Il est en gnral plus simple doptimiser la recherche pour une seule chane que pour plusieurs la fois. De mme, les recherches ancres peuvent souvent tre optimises si elles ne sont pas trop compliques. Vous navez pas vous limiter loprateur || pour le contrle de f lux. Vous pouvez souvent contrler les choses au niveau des instructions. Vous devriez toujours penser vous dbarrasser des cas les plus courants en premier. Supposons que vous criviez une boucle pour traiter un fichier de configuration. La plupart des fichiers de configuration sont composs principalement de commentaires. Cest souvent mieux de supprimer les commentaires et les lignes blanches avant de sattaquer aux lourds traitements, mme si les lourds traitements supprimeraient galement les commentaires et lignes blanches en cours de route :
while (<CONF>) { next if /^#/; next if /^\s*(#|$)/; chomp; meugneumeugneu($_); }

Mme si vous nessayez pas dtre efficace, vous avez souvent besoin dalterner entre les expressions Perl normales et les expressions rgulires, simplement parce que vous voulez faire quelque chose qui nest pas possible (ou qui est trs difficile) lintrieur dune expression rgulire, comme afficher quelque chose. Voici un classificateur de nombres bien utile :
warn warn warn warn warn warn warn "contient des non-chiffres" if /\D/; "pas un nombre naturel" unless /^\d+$/; # rejette -3 "pas un entier" unless /^-?\d+$/; # rejette +3 "pas un entier" unless /^[+-]?\d+$/; "pas un nombre dcimal" unless /^-?\d+\.?\d*$/; # rejette .2 "pas un nombre dcimal" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/; "pas un flottant de C" unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;

Nous pourrions encore beaucoup allonger cette section, mais ceci est vraiment le sujet de tout le livre. Vous verrez encore beaucoup dexemples mlant du code Perl et des recherches de motif au long du livre. En particulier, reportez-vous la section suivante Motifs programmatiques. (Mais vous pouvez quand mme commencer par lire ce qui suit, bien sr.)

customer_8566

172

Chapitre 5 Recherche de motif

Interpolation de variables
Lutilisation des mcanismes de contrle de f lux de Perl pour contrler les expressions rgulires a ses limites. La difficult principale est quil sagit dune approche tout ou rien ; soit vous faites tourner le motif, soit vous ne le faites pas tourner. Parfois vous savez vaguement ce que vous cherchez, mais vous aimeriez avoir la possibilit de le paramtrer. Linterpolation de variables fournit cette capacit, tout comme le paramtrage des sous-programmes vous permet davoir une plus grande inf luence sur leur comportement que simplement de choisir entre les appeler ou non. (Vous en verrez plus sur les sous-programmes au chapitre suivant.) Un des intrts de linterpolation est de fournir un peu dabstraction, ainsi quun peu de lisibilit. Avec des expressions rgulires, il est certes possible dcrire les choses de faon concise :
if ($num =~ /^[-+]?\d+\.?\d*$/) { ... }

Mais ce que vous voulez dire est plus comprhensible ainsi :


$signe = [-+]?; $chiffres = \d+; $point_decimal = \.?; $encore_des_chiffres = \d*; $nombre = "$signe$chiffres$point_decimal$encore_des_chiffres"; ... if ($num =~ /^$nombre$/o) { ... }

Nous couvrirons un peu plus cette utilisation de linterpolation dans la section Motifs gnrs, plus loin dans ce chapitre. Notez juste que nous avons utilis le modificateur /o pour supprimer la recompilation du motif, car nous ne nous attendons pas ce que $nombre change de valeur au cours du programme. Un autre truc sympa est de renverser vos tests et de vous servir de la chane variable comme motif vis--vis dun ensemble de chanes connues :
chomp($reponse if ("SEND" elsif ("STOP" elsif ("ABORT" elsif ("LIST" elsif ("EDIT" = <STDIN>); =~ /^\Q$reponse/i) =~ /^\Q$reponse/i) =~ /^\Q$reponse/i) =~ /^\Q$reponse/i) =~ /^\Q$reponse/i) { { { { { print print print print print "Action "Action "Action "Action "Action : : : : : send\n" stop\n" abort\n" list\n" edit\n" } } } } }

Ceci permet lutilisateur de lancer laction send en tapant S, SE, SEN ou SEND (dans nimporte quel mlange de majuscules et minuscules). Pour faire stop , il lui faudra au moins taper ST (ou St, sT ou st).

Retour de lantislash
Quand vous pensez linterpolation entre apostrophes doubles, vous pensez gnralement linterpolation des variables et des antislashs. Mais comme nous lavons indiqu prcdemment, il y a deux passes pour les expressions rgulires, et la passe dinterpolation laisse la plupart du travail dinterprtation des antislashs lanalyseur dexpressions rgulires (dont nous parlerons plus tard). Dordinaire, vous ne remarquerez pas de diffrence, car Perl fait bien attention les masquer. (Une squence qui est videm-

customer_8566

Garder le contrle

173

ment diffrente est le mtasymbole \b, qui se transforme en assertion de limite en dehors des classes de caractres, en tout cas. lintrieur dune classe de caractres, o les assertions nont aucun sens, il redevient un espace arrire, comme dhabitude.) Il est en fait assez important que lanalyseur de regex gre les antislashs. Imaginons que vous cherchiez les caractres de tabulation avec un motif sous le modificateur /x :
($col1, $col2) = /(.*?) \t+ (.*?)/x;

Si Perl ne laissait pas linterpolation de \t lanalyseur de regex, le \t se serait transform en un blanc que lanalyseur de regex aurait btement ignor cause du /x. Mais Perl nest ni si ignoble, ni si pigeant. Vous pouvez cependant vous piger tout seul. Imaginons que vous ayez un peu virtualis le sparateur de colonne, comme ceci :
$sepcol = "\t+"; # (apostrophes doubles) ($col1, $col2) = /(.*?) $sepcol (.*?)/x;

Et maintenant vous voil fait comme un rat, car le \t se transforme en vritable tabulation avant datteindre lanalyseur de regex, qui croira que vous avez crit /(.*?)+(.*?)/ une fois les blancs supprims. Oups. Pour corriger cela, vitez /x ou bien utilisez des apostrophes simples. Ou mieux, utilisez qr//. (Voir la section suivante.) Les seules squences dchappement entre apostrophes doubles qui sont traites comme telles sont les six squences de traduction : \U, \u, \L, \l, \Q et \E. Si jamais vous vous plongez un jour dans le fonctionnement interne du compilateur dexpressions rgulires, vous y trouverez du code destin grer les squences dchappement comme \t pour la tabulation, \n pour le saut de ligne, et ainsi de suite. Mais vous ny trouverez pas de code pour ces six squences de traduction. (Nous avons listes dans le tableau 5-7 uniquement car cest l quon sattend les trouver.) Si vous vous dbrouillez pour les inclure dans le motif sans passer par lvaluation entre apostrophes doubles, elles ne seront pas reconnues. Comment ont-elles pu sy glisser ? Vous pouvez contrecarrer linterpolation en utilisant des apostrophes simples comme dlimiteurs de motifs. Les apostrophes simples suppriment linterpolation de variables et le traitement des squences de traduction dans m..., qr... et s......, comme ils le feraient dans une chane entre apostrophes simples. crire m\ufrodon ne trouvera pas une version en majuscules de ce pauvre frodon. Cependant, comme les antislash normaux ne sont pas vraiment traits ce niveau, m\t\d trouvera toujours une vraie tabulation suivie dun chiffre quelconque. Une autre manire de contrecarrer linterpolation est de passer par linterpolation ellemme. Si vous crivez :
$var = \U; /${var}frodon/;

ce pauvre frodon reste en minuscules. Perl ne refera pas la passe dinterpolation pour vous simplement parce que vous avez interpol quelque chose qui a lair de vouloir tre interpol. Vous ne pouvez pas plus esprer que cela soit interpol que vous ne pourriez attendre que cette double interpolation marche :
$hobbit = Frodon; $var = $hobbit; /$var/; # (apostrophes simples) # signifie m$hobbit, et pas mFrodon.

customer_8566

174

Chapitre 5 Recherche de motif

Voici un autre exemple qui montre comment les antislashs sont interprts par lanalyseur de regex et pas par linterpolation de variables. Imaginons que vous ayez un petit utilitaire simple la grep :11
#!/usr/bin/perl $motif = shift; while (<>) { print if /$motif/o; }

Si vous appelez ce programme pgrep et linvoquez comme suit :


% pgrep \t\d *.c

alors vous dcouvrirez quil affiche toutes les lignes de tous vos fichiers source C dans lesquelles un chiffre suit une tabulation. Vous navez rien eu faire de spcial pour que Perl se rende compte que \t tait une tabulation. Si les motifs de Perl taient simplement interpols en contexte dapostrophes doubles, vous auriez d faire quelque chose ; heureusement ils ne le sont pas. Ils sont directement reconnus par lanalyseur de regex. Le vrai programme grep a une option -i qui rend la recherche insensible la casse. Vous navez pas besoin dajouter une telle option votre programme pgrep ; il peut dj le faire sans modification. Il suffit de lui passer un motif un peu plus labor, avec un modificateur /i inclus :
% pgrep (?i)anneau LotR*.pod

On cherche maintenant Anneau , anneau , ANNEAU et ainsi de suite. Vous ne verrez pas beaucoup cette fonctionnalit dans les motifs littraux, puisque vous pouvez simplement crire /anneau/i. Mais pour les motifs passs sur la ligne de commande, dans les formulaires web ou inclus dans les fichiers de configuration, cela peut savrer primordial.

Loprateur qr// de citation de regex


Les variables qui sont interpoles en motifs le sont ncessairement lexcution et non la compilation. Ceci ralentit lexcution, car Perl doit vrifier que vous navez pas chang le contenu de la variable ; si cest le cas, il faut alors recompiler lexpression rgulire. Comme mentionn dans Oprateurs de recherche de motifs, si vous promettez de ne jamais modifier le motif, vous pouvez utiliser loption /o pour interpoler et compiler une seule fois :
print if /$pattern/o;

Bien que cela fonctionne correctement dans notre programme pgrep, ce nest pas le cas en gnral. Imaginez que vous ayez une f loppe de motifs et que vous vouliez tous les tester dans une boucle, peut-tre comme ceci :
foreach $elem (@donnees) { foreach $motif (@motifs) {
11. Si vous ne saviez pas ce quest un programme comme grep, vous le saurez. Il ne devrait pas y avoir de systme sans grep nous pensons que grep est le plus utile des petits programmes jamais invents. (Ce qui logiquement indique que nous ne croyons pas que Perl soit un petit programme.)

customer_8566

Garder le contrle
if ($elem =~ /$motif/) { ... } } }

175

Vous ne pourriez pas crire /$motif/o, car la signification de $motif change chaque tour de la boucle interne. Ce problme est rsolu par loprateur qr/MOTIF/imosx. Cet oprateur cite et compile son MOTIF comme une expression rgulire. MOTIF est interpol de la mme faon que dans m/MOTIF/. Si est utilis comme dlimiteur, aucune interpolation de variable (ni des squences de traduction) nest faite. Loprateur renvoie une valeur Perl qui peut tre utilise la place de la chane littrale quivalente dans la recherche ou la substitution correspondante. Par exemple :
$regex = qr/ma.CHAINE/is; s/$regex/quelque chose dautre/;

est quivalent :
s/ma.CHAINE/quelque chose dautre/is;

Pour rsoudre notre problme prcdent de boucles embotes, vous pouvez donc dabord traiter le motif dans une boucle spare :
@regexes = (); foreach $motif (@motifs) { push @regexes, qr/$motif/; }

Ou bien dun seul coup en utilisant loprateur map de Perl :


@regexes = map { qr/$_/ } @motifs;

Puis modifier la boucle pour utiliser ces regex prcompiles :


foreach $elem (@donnees) { foreach $re (@regexes) { if ($elem =~ /$re/) { ... } } }

Dsormais quand vous faites tourner la recherche, Perl nest plus oblig de crer une expression rgulire compile chaque test if, car il se rend compte quil en possde dj une. Le rsultat dun qr// peut mme tre interpol dans un motif plus grand, comme sil sagissait dune simple chane :
$regex = qr/$motif/; $chaine =~ /toto${regex}titi/; # interpolation dans un motif plus grand

Cette fois Perl recompile le motif, mais vous pourriez chaner plusieurs oprateurs qr// en un seul. La raison pour laquelle cela fonctionne est que loprateur qr// retourne un objet spcial pour lequel la conversion en chane est surcharge comme dcrit au chapitre 13, Surcharge. Si vous affichez la valeur de retour, vous verrez la chane quivalente :
$re = qr/ma.CHAINE/is; print $re; # affiche (?si-xm:ma.CHAINE)

customer_8566

176

Chapitre 5 Recherche de motif

Les modificateurs /i et /s ont t activs dans le motif car ils ont t fournis qr//. De mme, /x et /m sont dsactivs car ils nont pas t fournis. chaque fois que vous interpolez des chanes de provenance inconnue dans un motif, vous devriez tre prt traiter les exceptions renvoyes par le compilateur de regex, dans le cas o lon vous aurait pass une chane contenant des bestioles indomptables :
$re = qr/$motif/is; # peut schapper et vous mordre $re = eval { qr/$motif/is } || warn ... # pris dans une cage extrieure

Pour en savoir plus sur loprateur eval, voir le chapitre 29.

Le compilateur de regex
Aprs que la passe dinterpolation de variable est passe sur la chane, lanalyseur de regex a enfin une occasion dessayer de comprendre votre expression rgulire. ce niveau-l, il ny a plus grand chose qui peut mal se passer, sinon embrouiller les parenthses ou utiliser une squence de mtacaractres qui na aucun sens. Lanalyseur fait une analyse rcursive descendante de votre expression rgulire et si elle est correcte, la met sous une forme interprtable par le Moteur (voir la section suivante). La plupart des choses intressantes qui se passent dans lanalyseur sont lies loptimisation de votre expression rgulire afin quelle soit excute le plus rapidement possible. Nous ne chercherons pas expliquer cette partie-l. Cest un secret de fabrication. (Ne croyez pas les rumeurs qui disent que regarder le code li aux expressions rgulires vous rendra fou ; elles sont trs exagres. Esprons-le.) Mais vous pourriez avoir envie de savoir ce que lanalyseur a vraiment pens de votre expression rgulire. Si vous lui demandez poliment, il vous le dira. En utilisant use re "debug";, vous pouvez examiner le traitement de votre motif par lanalyseur. (Vous pouvez galement obtenir la mme information en utilisant loption de ligne de commande -Dr. Celle-ci est disponible si votre Perl a t compil avec loption -DDEBUGGING lintallation.)
#!/usr/bin/perl use re "debug"; "Smeagol" =~ /^Sm(.*)g[aeiou]l$/;

La sortie suit. Vous pouvez voir quavant lexcution Perl compile la regex et donne une signification aux composantes du motif : BOL pour le dbut de ligne (^ ou Beginning Of Line), REG_ANY pour le point, et ainsi de suite :
Compiling REx `^Sm(.*)g[aeiou]l$ size 24 first at 2 rarest char l at 0 rarest char S at 0 1: BOL(2) 2: EXACT <Sm>(4) 4: OPEN1(6) 6: STAR(8) 7: REG_ANY(0) 8: CLOSE1(10) 10: EXACT <g>(12) 12: ANYOF[aeiou](21)

customer_8566

Garder le contrle
21: EXACT <l>(23) 23: EOL(24) 24: END(0) anchored `Sm at 0 floating `l$ at 4..2147483647 (checking anchored) anchored(BOL) minlen 5

177

Certaines de ces lignes rsument les conclusions de loptimiseur de regex. Il sait que la chane doit commencer par Sm et quil ny a donc aucune raison de faire lhabituelle recherche de gauche droite. Il sait que la chane doit se terminer par un l et peut donc rejeter directement celles qui ne le sont pas. Il sait que la chane doit faire au moins cinq caractres de long, et peut donc ignorer toute chane plus courte que cela sans autre forme de procs. Il sait galement quels sont les caractres les moins courants dans chaque sous-chane constante, ce qui peut aider avec les chanes tudies par study. (Voir study au chapitre 29.) Ensuite il liste la faon dont le motif est excut :
Guessing start of match, REx `^Sm(.*)g[aeiou]l$ against `Smeagol... Guessed: match at offset 0 Matching REx `^Sm(.*)g[aeiou]l$ against `Smeagol Setting an EVAL scope, savestack=3 0 <> <Smeagol> | 1: BOL 0 <> <Smeagol> | 2: EXACT <Sm> 2 <Sm> <eagol> | 4: OPEN1 2 <Sm> <eagol> | 6: STAR REG_ANY can match 5 times out of 32767... Setting an EVAL scope, savestack=3 7 <Smeagol> <> | 8: CLOSE1 7 <Smeagol> <> | 10: EXACT <g> failed... 6 <Smeago> <l> | 8: CLOSE1 6 <Smeago> <l> | 10: EXACT <g> failed... 5 <Smeag> <ol> | 8: CLOSE1 5 <Smeag> <ol> | 10: EXACT <g> failed... 4 <Smea> <gol> | 8: CLOSE1 4 <Smea> <gol> | 10: EXACT <g> 5 <Smeag> <ol> | 12: ANYOF[aeiou] 6 <Smeago> <l> | 21: EXACT <l> 7 <Smeagol> <> | 23: EOL 7 <Smeagol> <> | 24: END Match successful! Freeing REx: `^Sm(.*)g[aeiou]l$

Si vous suivez le blanc au milieu de Smeagol, vous pouvez voir le Moteur aller au plus loin pour que le .* soit aussi gourmand que possible, puis revient en arrire jusqu trouver une faon pour le reste du motif de russir. Mais cest justement le sujet de la section suivante.

customer_8566

178

Chapitre 5 Recherche de motif

Le petit Moteur qui /(ne )?pouvait( pas)?/


Et maintenant nous aimerions vous raconter lhistoire du petit Moteur de Regex qui dit Je crois que jpeux. Je crois que jpeux. Je crois que jpeux. .12 Dans cette section, nous allons prsenter les rgles que le Moteur utilise pour effectuer les recherches de correspondance de motifs. Le Moteur est extrmement persvrant et travailleur. Il est tout fait capable de continuer travailler alors que vous croyiez quil aurait dj abandonn. Le Moteur nabandonne pas tant quil nest pas absolument sr quil ny a aucun moyen pour lui de trouver une correspondance entre le motif et la chane. Les rgles ci-dessous expliquent comment le Moteur croit quil peut aussi longtemps que possible, jusqu ce quil sache quil peut ou ne peut pas. Le problme de notre Moteur est quil ne sagit pas simplement de faire monter un train en haut dune colline. Il sagit de parcourir un espace (potentiellement) trs compliqu de possibilits, en se souvenant de l o il est pass ou pas. Le Moteur utilise un automate fini non dterministe (NFA, nondeterministic finite-state automaton) pour trouver une correspondance. Cela signifie simplement quil garde une trace de ce quil a et na pas essay, et quand cela ne donne aucun rsultat, il revient en arrire et essaye autre chose. Cest le retour arrire, ou backtracking. Le Moteur Perl est capable dexplorer un million de possibilits pour une partie de la recherche, pour les abandonner et aller la partie de recherche suivante, puis recommencer explorer pour celle-ci le mme million de possibilits. Le Moteur nest pas trs intelligent ; il est juste persvrant et exhaustif. Il est cependant possible dcrire des motifs efficaces qui noccasionnent pas trop de retours arrires inutiles. Quand on vous dit Les regex choisissent la correspondance la plus gauche la plus longue , cela signifie que Perl prfre la plus gauche la plus longue. Mais le Moteur ne sait pas quil privilgie quelque chose ce niveau. Le choix global rsulte de nombreux choix particuliers et indpendants. Voici ces choix :13 Rgle 1 Le Moteur essaye de trouver une correspondance aussi loin que possible gauche de la chane, afin que la totalit de lexpression rgulire corresponde selon la rgle 2. Le Moteur dmarre juste avant le premier caractre et essaye de faire correspondre la totalit de lexpression rgulire depuis ce point. Lexpression rgulire correspond si et seulement si le moteur atteint la fin de lexpression sans stre arrt la fin de la chane. Sil a trouv, il sarrte immdiatement il ne recherche pas sil existe une meilleure solution, mme si le motif peut correspondre la recherche de plusieurs autres manires. Sil narrive pas trouver une correspondance au motif la premire position de la

12. NdT : The little Engine that could est lhistoire dune petite locomotive qui tire un gros chargement de toutes ses forces sans abandonner. Elle est connue de beaucoup denfants amricains, mais na rien de remarquable si ce nest le I think I can. I think I can. I think I can... qui ressemble lgrement au bruit dun moteur vapeur (en anglais). 13. Certains de ces choix peuvent tre ignors si loptimiseur a son mot dire, ce qui revient faire des coupes dans un arbre de dcision. Dans le cadre de cette discussion, nous faisons comme si loptimiseur nexistait pas.

customer_8566

Garder le contrle

179

chane, il reconnat temporairement sa dfaite et va la position suivante de la chane, entre le premier et le deuxime caractres, puis ressaie nouveau toutes les possibilits. En cas de succs, il sarrte. Sinon, il continue plus avant dans la chane. La recherche de correspondance dans son ensemble ne sera considre comme un chec quaprs avoir essay de faire correspondre toute lexpression rgulire toutes les positions de la chane, y compris aprs le dernier caractre. Une chane de n caractres fournit donc en fait n + 1 positions o correspondre. Cest parce que les dbut et fin de correspondance se trouvent entre les caractres de la chane. Cette rgle surprend parfois les gens quand il crivent un motif tel que /x*/ qui recherche zro ou plus x . Si vous essayez ce motif sur une chane comme dix , il ne trouvera pas le x . Il trouvera en fait la chane nulle juste avant le d et nira jamais chercher plus loin. Si vous voulez trouver un ou plusieurs x, vous devriez plutt utiliser le motif /x+/. Voir les quantificateurs la rgle 5. Un corollaire cette rgle est que toute expression rgulire qui peut trouver la chane nulle est assure de correspondre la position la plus gauche de la chane (en labsence de toute assertion de largeur vide qui vrifie le contraire). Rgle 2 Quand le Moteur rencontre une alternative (aux lments spars par des |), que ce soit au niveau global ou au niveau du regroupement courant, il les essaie successivement de gauche droite, en sarrtant la premire correspondance qui assure le succs du motif dans son ensemble. Une alternative correspond une chane si un lment quelconque de lalternative correspond au sens de la rgle 3. Si aucun des lments de lalternative ne correspond, il retourne la rgle qui a invoqu cette rgle, qui est en gnrale la rgle 1, mais pourrait trs bien tre la rgle 4 ou 6 dans un regroupement. Cette rgle cherchera alors une nouvelle position o appliquer la rgle 2. Sil nexiste quun seul terme dalternative, alors celui-ci est vrifi ou non, et la rgle 2 est toujours valable. (Il nexiste pas de zro alternative, car une chane vide correspond toujours quelque chose de longueur nulle.) Rgle 3 Un terme donn dune alternative est vrifi si chacun de ses lments est lui aussi vrifi selon les rgles 4 et 5 (de faon ce que toute lexpression rgulire soit satisfaite). Un lment peut consister en une assertion, qui est rgie par la rgle 4, ou en un atome quantifi, qui est rgi par la rgle 5. Les lments choix multiples sont hirarchiss de la gauche vers la droite. Si les lments ne peuvent tre vrifis, le Moteur rebrousse chemin jusquau choix suivant selon la rgle 2. Les lments qui doivent tre vrifis squentiellement ne sont pas spars dans lexpression rgulire par quoi que ce soit de syntaxique ; ils sont simplement juxtaposs dans lordre dans lequel ils doivent tre vrifis. Lorsque vous cherchez /^toto/, vous demandez en fait la dtection de cinq lments les uns la suite des autres. Le premier est une assertion de longueur nulle et les quatre autres des lettres ordinaires qui se correspondent elles-mmes, lune aprs lautre, selon la rgle 5. Lordre hirarchique de gauche droite implique que dans un motif tel que :
/x*y*/

customer_8566

180

Chapitre 5 Recherche de motif

x* choisit une manire de correspondre, puis y* essaie toutes ses possibilits. Si cela choue, x* choisit alors sa deuxime possibilit, et fait ressayer toutes ses possibilits y*. Et ainsi de suite. Les lments droite varient plus vite , pour emprunter une expression au vocabulaire des tableaux multidimensionnels. Rgle 4 Si une assertion ne correspond pas la position courante, le Moteur revient en arrire la rgle 3 et ressaie les lments plus haut dans la hirarchie avec des choix diffrents. Certaines assertions sont plus fantaisistes que dautres. Perl connat beaucoup dextensions de regex, dont certaines sont des assertions de largeur nulle. Par exemple, lassertion positive de prvision (?=...) et lassertion ngative de prvision (?!...) ne correspondent en ralit aucun caractre, mais sassurent plutt que lexpression rgulire reprsente par ... correspondrait (ou non), si nous lavions essaye.14 Rgle 5 Un atome quantifi nest vrifi que si et seulement si latome lui-mme est vrifi un nombre de fois autoris par le quantificateur. (Latome est vrifi selon la rgle 6). Des quantificateurs diffrents impliquent un nombre diffrent de vrifications, et la plupart dentre eux permettent un nombre variable de vrifications. Les correspondances multiples doivent tre faites la suite, cest--dire quelles sont adjacentes dans la chane. Un atome non quantifi est suppos avoir un quantificateur ne demandant quune seule vrification (cest--dire que /x/ est identique /x{1}/). Si aucune correspondance nest trouve la position courante pour aucune des quantits autorises pour latome en question, le Moteur revient la rgle 3 et ressaye des lments dordre hirarchique plus lv avec des valeurs diffrentes. Les quantificateurs sont *, +, ?, *?, +?, ?? et les diffrentes formes daccolades. Si vous utilisez la forme {COMPTE}, alors il ny a pas le choix et latome doit correspondre le nombre exact de fois prcis, ou pas du tout. Sinon, latome peut tre recherch parmi un ensemble de possibilits de rptition, et le Moteur garde une trace de tous les choix pour revenir en arrire si besoin est. Mais la question est alors de savoir quel choix faire en premier. On pourrait commencer par le nombre maximal et le rduire au fur et mesure, ou dmarrer avec le nombre minimal et laugmenter petit petit. Les quantificateurs traditionnels (sans point dinterrogation la suite) spcifient une recherche gourmande ; cest--dire quils essaient de vrifier autant de caractres que possible. Pour trouver la correspondance maximale, le Moteur doit faire un petit peu attention. Les mauvais choix cotent potentiellement cher, cest pourquoi le Moteur ne compte pas vraiment partir de la valeur maximale, qui pourrait aprs tout tre Trs Grande et provoquer des millions de mauvais choix. Le Moteur fait en ralit quelque chose dun petit peu plus malin : il commence par compter

14. En ralit, elle est teste par le Moteur. Celui-ci retourne la rgle 2 pour tester le sous-motif, puis efface toute trace de ce qui avait t consomm de la chane, pour ne retourner que le succs ou lchec du sous-motif comme valeur de lassertion. (Il se souvient cependant de toute chane capture.)

customer_8566

Garder le contrle

181

de faon croissante combien datomes correspondants ( la suite) sont effectivement prsents dans la chane, puis utilise ce maximum rel comme premier essai. (Il se souvient aussi des choix les plus courts, au cas o le plus long ne marcherait pas.) Il essaie (enfin) de vrifier le reste du motif, en supposant que le choix le plus long est le bon. Si le choix le plus long ne produit de correspondance pour le reste du motif, il revient en arrire et essaie le plus long suivant. Si vous crivez /.*toto/ par exemple, il essayera de trouver le nombre maximum de caractres quelconques (reprsents par le point) jusqu la fin de la ligne avant mme de commencer chercher toto ; puis quand le toto ne correspond pas cet endroit (et il ne peut pas, puisquil ny a pas assez de place en fin de chane pour le trouver), le Moteur va reculer dun caractre la fois jusqu trouver un toto . Sil y a plus dun toto sur la ligne, il sarrtera au dernier, puisque ce sera en fait le premier quil rencontre au cours de sa remonte. Quand le motif complet russit en utilisant une longueur particulire de .*, le Moteur sait quil peut abandonner les autres choix plus courts pour .* (ceux quil aurait utiliss si le toto en cours navait finalement pas fonctionn). En mettant un point dinterrogration aprs nimporte quel quantificateur gourmand, vous le transformez en quantificateur frugal qui choisit la plus petite quantit pour son premier essai. Donc, si vous crivez /.*?toto/, le .*? essayera dabord de correspondre 0 caractres, puis 1, puis 2, et ainsi de suite jusqu trouver le toto . Au lieu de rebrousser chemin en arrire, il rebrousse chemin en avant, pour ainsi dire. Et finit par trouver le premier toto de la ligne au lieu du dernier. Rgle 6 Chaque atome correspond selon son type. Si latome nest pas vrifi (ou lest, mais que sa vrification ne permet pas de correspondance pour le reste du motif), le Moteur revient en arrire la rgle 5 et essaie le choix suivant possible en quantit pour cet atome. Les atomes correspondent selon les types suivants : Une expression rgulire entre parenthses, (...), trouve tout ce que lexpression rgulire reprsente par ... trouve selon la rgle 2. Les parenthses servent donc doprateur de regroupement pour la quantification. Les parenthses simples ont galement pour effet de capturer la sous-chane trouve pour une utilisation ultrieure comme rfrence arrire (ou backreference en anglais). Cet effet de bord peut tre supprim en utilisant plutt (?:...), qui na que les proprits de regroupement ; il ne stocke rien dans $1, $2 et autres. Il existe dautres formes datomes (et dassertions) entre parenthses voir la suite de ce chapitre. Un point correspond tout caractre, sauf ventuellement le saut de ligne. Une liste de caractres entre crochets (une classe de caractres) correspond nimporte lequel des caractres spcifis dans la liste. Une lettre prcde dun antislash correspond soit un caractre particulier, soit un caractre dun ensemble particulier, comme indiqu dans le tableau 5-7. Tout autre caractre prcd dun antislash correspond ce caractre lui-mme. Tout caractre non mentionn ci-dessus se correspond lui-mme.

customer_8566

182

Chapitre 5 Recherche de motif

Tout cela peut sembler plutt compliqu, mais lavantage est que pour chaque liste de choix donne par un quantificateur ou une alternative, le Moteur a un bouton tourner. Il tournera tous ces boutons jusqu ce que tout le motif corresponde. Les rgles ne font quindiquer dans quel ordre le Moteur peut tourner ces boutons. Dire que le Moteur prfre la correspondance la plus longue gauche signifie simplement que le bouton quil tourne le plus lentement est celui correspondant la position de dpart. Revenir en arrire consiste simplement tourner dans lautre sens le bouton tourn linstant de faon essayer un autre bouton plus haut dans lordre hirarchique, cest-dire un qui varie plus lentement. Voici un exemple plus concret sous la forme dun programme qui dtecte quand deux mots conscutif partagent un suffixe et un prfixe communs :
$a = conflit; $b = litige; if ("$a $b" =~ /^(\w+)(\w+) \2(\w+)$/) { print "$2 superpos dans $1-$2-$3\n"; }

Ceci affiche :
lit superpos dans conf-lit-ige

Vous pourriez croire que $1 capture dabord lintgralit de chienlit par gourmandise. Cest exactement ce quil fait dabord. Mais une fois rendu l, il ny a plus de caractres mettre dans $2, qui a besoin de recevoir des caractres cause du quantificateur +. Le Moteur bat donc en retraite et $1 donne contrecur un caractre $2. Cette fois lespace est trouv correctement, mais quand il voit le \2, qui reprsente un simple t . Le caractre suivant dans la chane nest pas un t , mais un l . Ceci fait donc revenir le Moteur en arrire et ressayer plusieurs fois, pour finalement forcer $1 laisser le lit $2. En fait, cela ne marchera pas forcment bien si la superposition elle-mme est un doublon, comme pour les mots rococo et cocon . Lalgorithme ci-dessus aurait simplement dcid que la chane en superposition, $2, devait tre co plutt que coco . Mais nous ne voulons pas de rocococon ; nous voulons plutt un rococon . Nous voici dans un cas o il est possible dtre plus malin que le Moteur. Lajout dun quantificateur minimal la partie correspondant $1 donne le motif bien meilleur /^(\w+?)(\w+) \2(\w+)$/, qui fait exactement ce que nous voulons. Pour une discussion plus dtaille des avantages et inconvnients des diffrentes sortes de moteurs dexpressions rationnelles, reportez-vous au livre de Jeffrey Friedl, Matrise des expressions rgulires (ou en version originale Mastering Regular Expressions). Le Moteur dexpressions rgulires de Perl fonctionne trs bien pour tous les problmes quotidiens que vous voulez rsoudre avec Perl, mais tout aussi correctement pour ce genre de problme pas si quotidien, pourvu que vous soyez un peu comprhensif.

customer_8566

Motifs tendus

183

Motifs tendus
Assertions priphriques
Parfois vous voulez juste jeter un il. Voici quatre extensions de regex qui vous aident justement faire cela. Nous les appelons priphriques (en anglais lookaround) car elles vous permettent de jeter un il alentour de faon hypothtique, sans correspondre effectivement des caractres. Ces assertions testent le fait quun motif correspondrait (ou non) dans le cas o nous lessayerions. Le Moteur fait cela en essayant effectivement de faire correspondre le motif puis en prtendant par la suite quil ny a pas eu de correspondance de faite (mme si cest le cas). Quand le Moteur regarde en avant par rapport sa position actuelle dans la chane, nous parlons dassertion de prvision15 (lookahead). Sil regarde en arrire, nous parlons dassertion de rtrovision. Les motifs de prvision peuvent tre nimporte quelle expression rationnelle, tandis que les motifs de rtrovision ne peuvent qutre de longueur fixe, car ils doivent savoir do partir pour leur correspondance hypothtique. Alors que ces quatre extensions sont toutes de largeur nulle, et ne consomment donc pas de caractres (du moins pas officiellement), vous pouvez en fait capturer des souschanes lintrieur si vous fournissez un niveau supplmentaire de parenthses de capture. (?=MOTIF) (positive de prvision) Quand le Moteur rencontre (?=MOTIF), il regarde en avant dans la chane pour sassurer que MOTIF se produit. Pour mmoire, dans notre prcdent suppresseur de doublons, nous avons d crire une boucle car notre motif consommait trop de texte chaque tour :
$_ = "Paris AU AU AU AU printemps." # supprime les doublons (et les triplons (et les quadruplons...)) 1 while s/\b(\w+) \1\b/$1/gi;

chaque fois que vous entendez consomme trop , vous devriez immdiatement penser assertion de pr-vision . (Enfin, presque toujours.) En regardant lavance au lieu de directement avaler le deuxime mot, vous pouvez crire un suppresseur de doublons qui fonctionne en une passe, comme ceci :
s/ \b(\w+) \s (?= \1\b ) //gxi;

videmment, il y a encore un problme, puisque cela va malmener des phrases parfaitement valides comme Jai une BELLE BELLE-mre . (?!MOTIF) (ngative de prvision) Quand le Moteur rencontre (?!MOTIF), il regarde en avant dans la chane pour sassurer que MOTIF napparat pas. Pour corriger notre exemple prcdent, nous pouvons ajouter une assertion ngative de prvision aprs lassertion positive pour
15. NdT : Ce terme et le suivant ne sont pas forcment trs heureux, cest pourquoi nous vous fournissons le vocabulaire original pour que vous soyez pas tonns en lisant des documentations utilisant ces termes.

customer_8566

184
liminer le cas des mots composs :
s/ \b(\w+) \s (?= \1\b (?! -\w))//xgi;

Chapitre 5 Recherche de motif

Ce \w final est ncessaire pour viter de confondre un mot compos avec mot suivi dun tiret. Nous pouvons mme aller plus loin, puisque plus tt dans ce chapitre nous nous sommes intentionnellement servis de lexpression nous nous sommes , et que nous aimerions que notre programme ne corrige pas cela pour nous. Nous pouvons donc ajouter une alternative lassertion ngative de pr-vision de manire ne pas corriger cela (et montrer ainsi que nimporte quel type de parenthses peut servir regrouper des alternatives) :
s/ \b(\w+) \s (?= \1\b (?! -\w | \s sommes))//gix;

Nous nous sommes maintenant assurs que cette formulation spcifique naura pas de problme. Hlas le pome Mes petites amoureuses de Rimbaud est toujours cass16. Aussi ajoutons-nous une nouvelle exception :
s/ \b(\w+) \s (?= \1\b (?! -\w | \s sommmes | \s aimions))//igx;

Voil qui commence semballer. Faisons plutt une Liste Officielle dExceptions, en utilisant un mignon petit truc dinterpolation avec la variable $" pour sparer les lments de lalternative avec le caractre | :
@nousnous = qw(sommes aimions); local $" = |; s/ \b(\w+) \s (?= \1\b (?! -\w | \s (?: @nousnous )))//xig;

(?<=PATTERN) (positive de rtrovision) When the Engine encounters (?<=PATTERN), it looks backward in the string to ensure that PATTERN already occurred. Notre exemple a toujours un problme. Bien que lon permette Rimbaud de dire Nous nous aimions , cela autorise galement La totalit des des sommes seront converties en Euros . Nous pouvons ajouter une assertion positive de rtrovision en tte de notre liste dexceptions pour nous assurer que nous nappliquons nos exceptions @nousnous qu un vrai nous nous .
s/ \b(\w+) \s (?= \1\b (?! -\w | (?<= nous) \s (?: @nousnous )))//ixg;

Oui, tout cela devient bien compliqu, mais rappelons que cette section sappelle Motifs tendus. Si vous avez besoin de compliquer encore le motif aprs ce que nous lui avons fait subir, lutilisation judicieuse des commentaires et de qr// devrait vous aider ne pas devenir fou. (?<!MOTIF) (ngative de rtrovision) Quand le Moteur rencontre (?<!MOTIF), il regarde en arrire dans la chane pour sassurer que MOTIF na pas t trouv. Essayons avec un exemple simple cette fois-ci. Pourquoi pas une rgle dorthographe facile ? Si vous ne savez plus si un mot se termine en euil ou en ueil , et

16. NdT : Trs exactement la troisime strophe :


Nous nous aimions cette poque, Bleu laideron ! On mangeait des ufs la coque Et du mouron !

customer_8566

Motifs tendus

185

que vous avez plutt la manie dcrire ueil (parce que vous tes n Rueil, par exemple). Lexpression rgulire suivante peut remettre les choses en ordre :
s/(?<!c|g)ueil/euil/g

Ne pas savoir crire fauteuil ou cerfeuil nest pas un cueil et ne doit pas blesser votre orgueil.

Sous-motifs sans retour arrire


Comme nous lavons dcrit dans Le petit Moteur qui /(ne )?pouvait( pas)?/ , le Moteur fait souvent machine arrire alors quil progresse le long dun motif. Vous pouvez empcher le Moteur de faire demi-tour au milieu dune srie de possibilits en crant un sous-motif sans retour arrire. Un sous-motif sans retour arrire se prsente comme (?>MOTIF), et fonctionne exactement comme un simple (?:MOTIF), sauf quune fois que MOTIF a trouv une correspondance, il supprime toute possibilit de retour arrire sur tous les quantificateurs ou alternatives lintrieur du sous-motif. (Cest pourquoi il est inutile dutiliser cela sur un MOTIF qui ne contient pas de quantificateurs ou dalternatives.) La seule manire de le faire changer davis est de rebrousser chemin jusqu quelque chose avant ce sous-motif et de rentrer dans le sous-motif par la gauche. Cest comme rendre visite un concessionaire automobile. Aprs un certain temps de discussion sur le prix, vous finissez par donner un ultimatum : Voici ma meilleure offre : cest prendre ou laisser. . Sils ne la prennent pas, vous ne recommencez pas marchander. Vous oprez un retour arrire vers la porte. Vous pouvez ensuite aller voir un autre concessionaire et recommencer marchander. Vous pouvez recommencer marchander, mais seulement parce que vous tes rentr dans le sous-motif sans retour arrire dans un contexte diffrent. Pour les adorateurs de Prolog ou SNOBOL, vous pouvez voir cela comme un oprateur cut ou fence porte limite. Voyons comment dans "aaab" =~ /(?:a*)ab/, le a* commence par trouver trois a, puis en laisse un car le dernier a est utilis plus loin. Le sous-motif sacrifie une partie de son butin pour permettre toute la correspondance de russir. (Ce qui revient laisser le marchand de voitures obtenir un peu plus de votre argent par peur de ne pas pouvoir conclure laffaire.) En revanche, le sous-motif dans "aaab" = ~ /(?>a*)ab/ nabandonnera rien de ce quil a pu trouver, mme si cette attitude fait chouer la correspondance toute entire. Bien que (?>MOTIF) soit utile pour modifier le comportement dun motif, il est souvent utilis pour acclrer lchec de certaines recherches dont vous savez quelles vont chouer ( moins quelles ne russissent tout fait). Le Moteur peut prendre un temps extraordinairement long pour chouer, en particulier avec des quantificateurs embots. Le motif suivant russira de faon quasi-instantane :
$_ = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"; /a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*[b]/;

Mais ce nest pas le succs qui est un problme. Cest lchec qui en est un. Si vous retirez ce b final de la chane, le motif va probablement tourner pendant des annes et des annes avant dchouer. Pendant des millnaires et des millnaires. En ralit des mil-

customer_8566

186

Chapitre 5 Recherche de motif

liards et des milliards dannes.17 Vous pouvez constater en examinant le motif quil ne peut russir sil ny a pas de b la fin de la chane ; mais loptimiseur nest pas assez malin (au moment o nous crivons ces lignes) pour se rendre compte que /[b]/ est quivalent /b/. Mais si vous lui donnez un indice, vous pouvez le faire chouer rapidement tout en le laissant russir l o il peut :
/(?>a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*)[b]/;

Voici un exemple plus raliste (esprons). Imaginez un programme qui est suppos lire paragraphe par paragraphe et nafficher que les lignes qui se continuent, les lignes de continuation tant spcifies par un antislash final. Voici un exemple tir du Makefile de Perl qui utilise cette convention :
# Files to be built with variable substitution before miniperl # is available. sh = Makefile.SH cflags.SH config_h.SH makeaperl.SH makedepend.SH \ makedir.SH myconfig.SH writemain.SH

Vous pourriez crire votre programme de cette faon :


#!/usr/bin/perl -00p while ( /( (.+) ( (?<=\\) \n .* )+ ) /gx) { print "Jai $.: $1\n\n"; }

a marche, mais cest vraiment trs lent. Cest parce que le Moteur fait machine arrire un caractre la fois depuis la fin de la ligne, en diminuant ce qui se trouve dans $1. Cest sans intrt. Lcrire sans les captures surnumraires namliore pas sensiblement les choses. Utiliser :
(.+(?:(?<=\\)\n.*)+)

pour un motif est un peu plus rapide, mais pas tellement. Cest dans ce cas quun motif sans retour arrire est trs utile. Le motif :
((?>.+)(?:(?<=\\)\n.*)+)

fait la mme chose, mais est plus rapide dun ordre de grandeur. Cest parce quil ne perd pas son temps chercher quelque chose qui nest pas l. Il nest pas possible dobtenir avec (?>...) un succs que vous nauriez obtenu avec (?:...) ou mme un simple (...). Mais si votre recherche doit chouer, autant chouer rapidement et passer la suite.

Motifs programmatiques
La plupart des programmes Perl sont crits dans un style impratif (aussi appel procdural). Cest un peu comme une suite dordres lists dans un facile suivre : Prchauffer le four, mlanger, glacer, cuire, laisser refroidir, servir aux martiens. . Parfois vous rajoutez ce mlange une bonne cuillere de programmation fonctionnelle ( Utilisez un peu plus de glacage que vous ne pensez en avoir besoin, mme aprs
17. En fait, cest plutt de lordre des septillions dannes. Nous ne savons pas exactement combien de temps cela prendrait. Nous navons pas eu la patience dattendre de le voir chouer. En tous les cas, votre ordinateur risque fort de planter avant que lunivers ne disparaisse, et cette expression rgulire met plus de temps que ces deux vnements se produire.

customer_8566

Motifs tendus

187

avoir tenu compte de ce conseil, rcursivement ) ou vous le saupoudrez de quelques techniques orientes-objet ( Merci de laisser les objets anchois de ct ). Souvent cest un mlange de tout cela la fois. Mais le Moteur dexpressions rgulires a une approche compltement diffrente de la rsolution de problmes, une approche plus dclarative. Vous dcrivez vos objectifs dans le langage des expressions rgulires, et le Moteur implmente la logique ncessaire pour atteindre vos objectifs. Les langages de programmation logique (comme Prolog) ont une moins grande visibilit que les trois autres styles, mais ils sont plus rpandus que vous ne pourriez le croire. Perl ne pourrait mme pas tre construit sans make ou yacc ; tous deux pouvant tre considrs, sinon comme des langages purement dclaratifs, au moins comme des hybrides qui mlangent la programmation imprative et la programmation logique. Vous pouvez aussi faire ce genre de choses en Perl, en mlangeant ensemble des dclarations dobjectifs avec du code impratif, de faon encore plus f luide que nous ne lavons fait jusqu prsent afin de profiter des forces de chacun. Vous pouvez construire programmatiquement la chane que vous allez finir par proposer au Moteur de regex, cest--dire dune certaine manire crer un programme qui crit un nouveau programme la vole. Vous pouvez galement fournir des expressions Perl normales comme remplacement dans s/// laide du modificateur /e. Ceci vous permet de gnrer dynamiquement la chane de remplacement en excutant un morceau de code chaque fois que le motif correspond. Dune manire encore plus labore, vous pouvez inclure des bouts de code partout o vous le voulez au beau milieu dun motif en utilisant lextension (?{CODE}). Celui-ci sera excut chaque fois que le Moteur rencontrera ce code, au fur et mesure de ses prgrinations, dans la danse complique des retours en arrire. Enfin, vous pouvez utiliser s///ee ou (??{CODE}) pour ajouter un nouveau niveau dindirection : le rsultat de lexcution de ces bouts de code sera lui-mme rvalu pour tre rutilis, crant des morceaux de programme et de motif au vol, juste temps.

Motifs gnrs
Il a t dit18 que les programmes qui crivent des programmes sont les programmes les plus heureux au monde. Dans le livre de Jeffrey Friedl, Matrise des expressions rgulires (Mastering Regular Expressions), le tour de force final montre comment crire un programme qui produit une expression rgulire capable de dterminer si une chane est conforme au standard dfini par le RFC 822 ; cest--dire sil contient un en-tte de mail conforme au standard. Le motif produit fait plusieurs milliers de caractres de long, et est aussi facile lire quun dump mmoire binaire aprs un crash. Mais le dtecteur de motif de Perl sen moque ; il compile juste le motif sans difficult et, ce qui est encore plus intressant, lexcute trs rapidement bien plus rapidement, en fait, que beaucoup de motifs beaucoup plus courts qui ont des besoins de retour arrire plus compliqus. Cest un exemple trs compliqu. Nous vous avons prcdemment montr un exemple trs simple de la mme technique quand nous avons fabriqu un motif $nombre partir
18. Par Andrew Hume, le clbre philosophe Unix.

customer_8566

188

Chapitre 5 Recherche de motif

de ses lments constitutifs (voir la section Interpolation de variables). Mais pour vous montrer la puissance de lapproche programmatique pour la production dun motif, nous allons nous pencher sur un problme de complexit moyenne. Supposons que vous vouliez trouver tous les exemples de mots avec une certaine suite de voyelles et de consonnes ; par exemple audio et aeree suivent tous deux un motif VVCVV Mme si dcrire ce qui compte comme voyelle ou consonne est simple19, . vous naurez pas vraiment envie de lcrire plus dune fois. Mme pour un cas simple comme notre VVCVV vous devrez crire un motif comme : ,
^[aeiouy][aeiouy][bcdfghjklmnpqrstvwxzy][aeiouy][aeiouy]$

Un programme plus gnral accepterait une chane comme VVCVV pour gnrer (programmatiquement) le motif pour vous. Pour tre mme encore plus f lexible, il pourrait mme accepter un mot comme audio , lutiliser comme modle pour en dduire VVCVV et de l construire le long motif ci-dessus. Cela a lair compliqu, mais ne lest vraiment pas, car nous allons laisser le programme gnrer le motif pour nous. Voici un simple programme cvmap qui fait tout cela :
#!/usr/bin/perl $voyelles = aeiouy; $consonnes = bcdfghjklmnpqrstvwxzy; %assoc = (C => $consonnes, V => $voyelles); # initialise la liste pour V et C for $classe ($voyelles, $consonnes) { # pour chaque type for (split //, $class) { # rcupre chaque lettre de chaque type $assoc{$_} .= $class; # et rassocie chaque lettre chaque type } } for $char (split //, shift) { $motif .= "[$assoc{$char}]"; approprie } $re = qr/^${motif}$/i; print "REGEX : $re\n"; @ARGV = (/usr/dict/words) if -t && !@ARGV; while (<>) { print if /$re/; } # pour chaque lettre du modle # ajoute la classe de caractres

# compile le motif # affiche une vrification # prend un dictionnaire par dfaut

# et maintenant parcourt lentre # en affichant les lignes qui # correspondent

19. NdT : Plus simple en anglais quen franais, car nos classes de caractres seraient plutot [aeiouy] pour les voyelles et [bcdefghjklmnpqrstvwxyz] pour les consonnes. Et nous ne vous parlons mme pas des ligatures ! Dans les exemples qui suivent, le dictionnaire utilis est une version sans accents. Ladaptation pour traiter les accents est laisse en exercice au lecteur. Notez cependant que use locale; vous facilitera les \w.

customer_8566

Motifs tendus

189

La variable %assoc contient tous les morceaux intressants. Elle utilise chaque lettre de lalphabet comme cl, et la valeur correspondante est lensemble des lettres du mme type. Nous ajoutons galement V et C, pour que vous puissiez utiliser VVCVV ou audio et tout de mme obtenir aeree . Chaque caractre de largument fourni est utilis pour trouver la classe de caractres associe et lajouter au motif. Une fois le motif cr et compil par qr//, la correspondance (mme si le motif est trs long) va tourner rapidement. Voici un extrait de ce que vous pourriez obtenir en faisant tourner ce programme fortuitement :
% cvmap fortuitement /usr/dict/words_fr REGEX : (?i-xsm:^[cbdfghjklmnpqrstvwxzy][aeiouy][cbdfghjklmnpqrstvwxzy][cbd fghjklmnpqrstvwxzy][aeiouy][aeiouy][cbdfghjklmnpqrstvwxzy][aeiouy][cbdfghjk lmnpqrstvwxzy][aeiouy][cbdfghjklmnpqrstvwxzy][cbdfghjklmnpqrstvwxzy]$) banqueterent becqueterent bestialement biscuiterent cabriolerent cabriolerons cabrioleront certainement circuiterent ...

En vous laissant admirer cette REGEX, nous vous persuaderons verbeusement mais certainement de lconomie de frappe ainsi sommairement ralise.

valuations de substitution
Quand le modificateur /e ( e pour valuation dexpression) est utilis sur une expression s/MOTIF/CODE/e, la partie de remplacement est interprte comme une expression, et pas seulement comme une chane entre apostrophes doubles. Cest comme un do {CODE}. Mme si cela a lair dune chane, cest simplement un bloc de code qui sera compil en mme temps que le reste de votre programme, bien avant que la substitution ne soit rellement faite. Vous pouvez utiliser le modificateur /e pour construire des chanes de remplacement avec une logique plus fantaisiste que celle que permet linterpolation entre doubles apostrophes. Voici la diffrence :
s/(\d+)/$1 * 2/; s/(\d+)/$1 * 2/e; # Remplace "42" par "42 * 2" # Remplace "42" par "84"

Et ceci convertit les degrs Celsius en Fahrenheit :


$_ = "Prchauffez le four 233C.\n"; s/\b(\d+\.?\d*)C\b/int($1 * 1.8 + 32) . "F"/e; # convertit en 451F

Les applications sont sans limite. Voici un filtre qui modifie un fichier en place (comme un diteur) en ajoutant 100 tout nombre qui se trouve en dbut de ligne (et qui nest pas suivi par des deux-points, que nous ne faisons que regarder, sans les trouver ni les remplacer) :
% perl -pi -e s/^(\d+)(?=:)/100 + $1/e fichier

customer_8566

190

Chapitre 5 Recherche de motif

De temps autre, vous voudrez faire un peu plus que simplement utiliser dans un autre calcul la chane que vous avez trouve. Vous voulez parfois que cette chane soit un calcul, dont vous utiliserez lvaluation en tant que valeur de remplacement. Chaque modificateur /e supplmentaire rajoute un eval autour du code excuter. Les deux lignes suivantes font la mme chose, mais la premire est plus facile lire :
s/MOTIF/CODE/ee s/MOTIF/eval(CODE)/e

Vous pourriez utiliser cette technique pour remplacer les apparitions de valeurs scalaires simples par leurs valeurs :
s/(\$\w+)/$1/eeg; # Interpole les valeurs de la plupart des scalaires

Comme cest vraiment un eval, le /ee trouve mme les variables lexicales. Un exemple un peu plus labor calcule la valeur de remplacement pour des expressions arithmtiques simples sur des entiers (positifs) :
$_ = "Jai 4 + 19 euros et 8/2 centimes.\n"; s{ ( \d+ \s* # trouve un entier [+*/-] # et un oprateur arithmtique \s* \d+ # et un autre entier ) }{ $1 }eegx; # puis trouve $1 et excute ce code print; # "Jai 23 euros et 4 centimes."

Comme tout autre eval CHAINE, les erreurs de compilation (comme des problmes de syntaxe) et les exceptions lexcution (comme une division par zro) sont captures. Dans ce cas, la variable $@ ($EVAL_ERROR) dit ce qui sest mal pass.

valuation de code lors de la recherche


Dans la plupart des programmes qui utilisent les expressions rgulires, ce sont les structures de contrle du programme tout autour qui dirigent le f lux logique de lexcution. Vous crivez des boucles if ou while, faites des appels de fonctions ou de mthodes, qui se trouvent appeler une opration de recherche de motif de temps autre. Mme avec s///e, cest loprateur de substitution qui a le contrle et nexcute le code de remplacement quaprs une recherche russie. Avec les sous-motifs de code, la relation usuelle entre les expressions rgulires et le code du programme est inverse. Alors que le Moteur applique ses rgles votre motif au moment de la recherche, il peut tomber sur une extension de regex de la forme (?{CODE}). Quand il est dclench, ce sous-motif ne fait aucune reconnaissance ni aucune assertion priphrique. Cest une assertion de largeur nulle qui russit toujours et nest value que pour ses effets de bord. chaque fois que le moteur doit passer sur le sous-motif de code pour progresser dans le motif, il excute ce code.
"glyphe" =~ /.+ (?{ print "yo" }) ./x; # Affiche "yo" deux fois.

Alors que le Moteur essaie dtablir la correspondance entre glyphe et ce motif, il laisse dabord .+ avaler les cinq lettres. Puis il affiche yo . Quand il tombe sur le point final, les cinq lettres ont dj t avales ; il lui faut donc faire machine arrire sur le .+ et lui faire rendre une des lettres. Il avance de nouveau dans le motif, faisant un nouvel affichage de yo au passage, fait correspondre e au point final et termine sa recherche avec succs.

customer_8566

Motifs tendus

191

Les accolades autour du fragment de CODE sont destines vous rappeler quil sagit dun bloc de code Perl, et quil se comporte comme un bloc au sens lexical. Cest--dire que si vous utilisez my pour dclarer une variable porte lexicale, elle sera prive ce bloc. Mais si vous utilisez local pour localiser une variable porte dynamique, il risque de ne pas faire ce quoi vous vous attendez. Un sous-motif (?{CODE}) cre une porte dynamique implicite qui reste valide pour le reste du motif, jusqu ce quil russisse ou quil fasse machine arrire travers ce sous-motif de code. Une manire de voir cela est que le bloc ne retourne pas vraiment quand il arrive la fin. Au lieu de cela, il faut un appel rcursif invisible au Moteur pour essayer de dtecter le reste du motif. Cest seulement quand cet appel rcursif se termine quil revient du bloc, en dlocalisant les variables localises.20 Dans lexemple suivant, nous initialisons $i 0 en incluant un sous-motif de code au dbut du motif. Ensuite nous capturons autant de caractres que possible avec .* mais nous mettons un autre sous-motif de code entre le . et l* comme cela nous pourrons savoir combien de fois le . trouve quelque chose.
$_ = lothlorien; m/ (?{ $i = 0 }) (. (?{ $i++ }) lori /x; # # # # Met $i 0 Met jour $i, mme aprs un retour en arrire Force un retour arrire

)*

Le Moteur se met donc joyeusement en route, mettant $i 0 et laissant .* gober les 10 caractres de la chane. Quand il recontre le lori dans le motif, il revient en arrire et abandonne quatre caractres du .*. la fin de la recherche, $i vaudra toujours 10. Si vous vouliez que $i reprsente le nombre de caractres que le .* a effectivement conservs la fin, vous pouvez utiliser la porte dynamique lintrieur du motif :
$_ = lothlorien; m/ (?{ $i = 0 }) (. (?{ local $i = $i + 1; }) )* # Met jour $i, avec protection contre le retour arrire lori (?{ $resultat = $i }) # Copie dans une variable non localise /x;

Ici nous utilisons local pour nous assurer que $i contient le nombre de caractres trouvs par .*, en tenant compte des retours en arrire. $i sera perdue aprs la fin de lexpression rgulire, aussi le sous-motif de code (?{ $result = $i }) conserve la valeur de $i dans $resultat.
20. Les personnes familires des analyseurs rcursif descendants pourront trouver ce comportement perturbant parce que de tels compilateurs retournent dun appel de fonction rcursif ds quils arrivent trouver quelque chose. Le Moteur ne fait pas cela quand il trouve quelque chose, il descend plus profond en recursion (mme quand il sort dun groupe entre parenthses !). Un analyseur rcursif descendant est un minimum de rcursion quand il russit la fin, mais le Moteur est un maximum de rcursion quand il russit la fin du motif. Vous pourriez trouver utile de faire pendre le motif par son extrmit gauche et de le voir comme une reprsentation de larbre des appels. Si vous arrivez visualiser cette image, la porte dynamique des variables locales vous sera plus comprhensible. (Et si vous ne pouvez pas, ce nest pas pire quavant.)

customer_8566

192

Chapitre 5 Recherche de motif

La variable spciale $^R (dcrite au chapitre 28) contient le rsultat du dernier (?{CODE}) qui a t excut au cours dune recherche russie. Vous pouvez utiliser une extension (?{CODE}) comme la COND dune (?(COND)SIVRAI|SIFAUX). Si vous faites cela, $^R ne sera pas mis jour et vous pouvez omettre les parenthses autour de la condition :
"glyphe" =~ /.+(?(?{ $toto{titi} gt "symbole" }).|signet)./;

Ici, nous testons si $toto{titi} est plus grand que symbole. Si oui, nous incluons . dans le motif, sinon nous incluons signet dans le motif. On peut ltirer pour le rendre un peu plus lisible :
"glyphe" =~ m{ .+ # quelques nimporte quoi (?(?{ # si $toto{titi} gt "symbole" # ceci est vrai }) . # trouve un autre nimporte quoi | # sinon signet # trouve signet ) . # et un nimporte quoi de plus }x;

Quand use re eval est enclench, une regex a le droit de contenir un sous-motif (?{CODE}) mme si lexpression rgulire interpole des variables :
/(.*?) (?{length($1) < 3 && warn}) $suffixe/; # Erreur sans use re eval

Ceci est normalement interdit pour des raisons de scurit. Mme si le motif ci-dessus est sans danger car $suffixe est sans danger, lanalyseur de regex ne peut pas savoir quelles parties de la regex ont t interpoles et lesquelles ne lont pas t. Cest pourquoi il interdit simplement les sous-motifs de code sil y a eu de linterpolation. Si le motif sobtient partir de donnes entaches, mme use re eval nautorisera pas la recherche de motif continuer. Quand use re taint est enclench et quune chane entache est la cible dune regex, les sous-motifs capturs (dans les variables numrotes ou dans la liste de valeurs renvoyes par m// en contexte de liste) sont entachs. Cela est utile quand les oprations de regex sur des donnes entaches sont destines non pas extraire des sous-chanes sres, mais plutt pour faire de nouvelles transformations. Voir le chapitre 23, Scurit, pour en savoir plus sur lentachement. Pour ce pragma, les expressions rgulires prcompiles (obtenues en gnral par qr//) ne sont pas considres comme interpoles :
/toto${motif}titi/

Ceci est autoris si $motif est une expression rgulire prcompile, mme si $motif contient des sous-motifs (?{CODE}). Prcdemment nous vous avons montr un peu de ce que use re debug affiche. Une solution de dboguage un peu plus primitive consiste utiliser des sous-motifs (?{CODE}) pour afficher ce qui a t trouv jusquici dans la recherche :
"abcdef" =~ / .+ (?{print "Trouv jusqu prsent : $&\n"}) bcdef $/x;

Ceci affiche :

customer_8566

Motifs tendus
Trouv Trouv Trouv Trouv Trouv Trouv jusqu jusqu jusqu jusqu jusqu jusqu prsent prsent prsent prsent prsent prsent : : : : : : abcdef abcde abcd abc ab a

193

ce qui montre .+ gobant toutes les lettres et les rendant une par une au fur et mesure que le Moteur rebrousse chemin.

Interpolation de motif lors de la recherche


Vous pouvez construire des morceaux de votre motif depuis lintrieur du motif lui-mme. Lextension (??{CODE}) vous permet dinsrer du code qui svalue en un motif valide. Cest comme crire /$motif/, sauf que vous pouvez gnrer $motif lexcution plus spcifiquement, lors de la recherche. Par exemple :
/\w (??{ if ($seuil > 1) { "rouge" } else { "bleu" } }) \d/x;

Cest quivalent /\wrouge\d/ si $seuil est plus grand que 1 et /\wbleu\d/ sinon. Vous pouvez inclure des rfrences arrires lintrieur du code valu pour dduire de motifs de chanes trouves linstant (mme si elles ne seront plus trouves plus tard pour cause de retour arrire). Par exemple, ceci trouve toutes les chanes qui se lisent de la mme faon lenvers et lendroit (plus connues sous le nom de palindromadaires, ce sont des phrases avec une bosse au milieu) :
/^ (.+) .? (??{quotemeta reverse $1}) $/xi;

Vous pouvez quilibrer des parenthses comme suit :


$texte =~ /( \(+ ) (.*?) (??{ \) x length $1 })/x;

Ceci trouve les chanes de la forme (shazam!) et (((shazam!))), et met shazam! dans $2. Hlas, il est incapable de savoir si les parenthses au milieu sont quilibres. Pour cela nous avons besoin de rcursion. Heureusement, vous pouvez aussi faire des motifs rcursifs. Vous pouvez avoir un motif compil utilisant (??{CODE}) et faisant rfrence lui-mme. La recherche rcursive est plus irrgulire, pour des expressions rgulires. Tous les textes sur les expressions rgulires vous diront quune expression rationnelle standard ne peut pas trouver des parenthses quilibres correctement. Et cest correct. Il est aussi vrai que que les regex de Perl ne sont pas standard. Le motif suivant21 trouve un ensemble de parenthses quilibres, quelle que soit leur profondeur :
$pe = qr{ \( (?: (?> [^()]+ ) | (??{ $pe }) )*
21. Remarquez que vous ne pouvez pas dclarer la variable dans linstruction o vous allez lutiliser. Vous pouvez toujours la dclarer avant, bien sr.

# Non parenthses sans retour arrire # Groupe avec des parenthses quilibres

customer_8566

194
\) }x;

Chapitre 5 Recherche de motif

Vous pourriez lutiliser comme ceci pour trouver un appel de fonction :


$foncmotif = qr/\w+$pe/; mafonc(1,(2*(3+4)),5) =~ /^$foncmotif$/; # Trouv !

Interpolation conditionnelle
Lextension de regex (?(COND)SIVRAI|SIFAUX) ressemble loprateur ?: de Perl. Si COND est vrai, le motif SIVRAI est utilis ; sinon le motif SIFAUX est utilis. COND peut tre une rfrence arrire (exprim comme un entier simple, sans le \ ou le $), une assertion priphrique ou un sous-motif de code (voir Assertions priphriques et valuation de code lors de la recherche plus haut dans ce chapitre). Si COND est un entier, il est trait comme une rfrence arrire. Par exemple :
#!/usr/bin/perl $x = Perl est gratuit.; $y = PatronGiciel cote 99EUR.; foreach ($x, $y) { /^(\w+) (?:est|(cote)) (?(2)(\d+EUR)|\w+)/; # Soit (\d+EUR), soit \w+ if ($3) { print "$1 cote de largent.\n"; # PatronGiciel cote # de largent. } else { print "$1 ne cote rien.\n"; # Perl ne cote rien. } }

Ici, COND est (2), qui est vrai sil existe une deuxime rfrence arrire. Si cest le cas, (\d+EUR) est ajout au motif (et cre la rfrence arrire $3) ; sinon, \w+ est utilis. Si COND est un assertion priphrique ou un sous-motif de code, la vracit de lassertion est utilise pour dterminer sil faut inclure SIVRAI ou SIFAUX :
/[ATGC]+(?(?<=AA)G|C)$/;

Ceci utilise une assertion de rtrovision comme COND pour trouver une squence dADN qui se termine soir par AAG ou une autre combinaison de bases et un C.

Dfinir vos propres assertions


Vous ne pouvez pas modifier le fonctionnement du Moteur de Perl, mais si vous tes suffisament cingl, vous pouvez changer la faon dont il voit votre motif. Comme Perl interprte votre motif de manire analogue une chane entre apostrophes doubles, vous pouvez utiliser les merveilles de la surcharge des constantes chane pour vous arranger pour que les suites de caractres de votre choix soient automatiquement transformes en dautres suites de caractres. Dans lexemple qui suit, nous dfinissons deux transformations qui doivent se produire quand Perl rencontre un motif. Dabord nous dfinissons \tag de faon ce que lorsquil apparat dans un motif, il est automatiquement transform en (?:<.*?>), qui trou-

customer_8566

Motifs tendus

195

ve la plupart des balises HTML et XML. Ensuite, nous redfinissons le mtasymbole \w de faon ce quil naccepte que les lettres anglaises. Nous allons dfinir un paquetage nomm Tagger qui cache la surcharge notre programme principal. Une fois que cela est fait, nous pourrons crire :
use Tagger; $_ = <I>chameau</I>; print "Balise chameau trouve" if /\tag\w+\tag/;

Voici Tagger.pm, soit la forme dun module Perl (voir chapitre 11) :
package Tagger; use overload; sub import { overload::constant qr => \&convert } sub convert { my $re = shift; $re =~ s/ \\tag /<.*?>/xg; $re =~ s/ \\w /[A-Za-z]/xg; return $re; } 1;

Le module Tagger reoit le motif immdiatement avant linterpolation, aussi pouvez vous sauter la surcharge en sautant linterpolation, comme suit :
$re = \tag\w+\tag; print if /$re/; # Cette chane commence avec \t, une tabulation # Trouve une tabulation, suivie dun "a"...

Si vous vouliez personnaliser la variable interpole, appelez la fonction convert directement :


$re = \tag\w+\tag; $re = Tagger::convert $re; print if /$re/; # Cette chane commence avec \t, une tabulation # convertit \tag et \w # $re devient <.*?>[A-Za-z]+<.*?>

Et maintenant, si vous vous demandez toujours ce que sont ces fameuses sub dans le module Tagger, vous allez le dcouvrir bien vite, car cest le sujet du chapitre suivant.

customer_8566

customer_8566

Sous-programmes

Comme beaucoup de langages, Perl fournit des sous-programmes dfinis par lutilisateur.1 Ces sous-programmes peuvent tre dfinis nimporte o dans le programme principal, chargs depuis dautres fichiers grce aux mots-cls do, require ou use ou gnrs lexcution avec eval. Vous pouvez mme les charger lexcution avec le mcanisme dcrit dans la section Autochargement du chapitre 10, Paquetages. Vous pouvez appeler un sous-programme indirectement, en utilisant une variable contenant son nom ou une rfrence la routine ou travers un objet, en laissant lobjet dterminer quel sousprogramme doit vraiment tre appel. Vous pouvez gnrer des sous-programmes anonymes, accessibles seulement travers des rfrences, et si vous voulez, vous en servir pour cloner de nouvelles fonctions quasiment identiques laide de fermetures, qui sont dcrites dans la section du mme nom du chapitre 8, Rfrences.

Syntaxe
Pour dclarer un sous-programme nomm sans le dfinir, utilisez lune de ces formes :
sub sub sub sub sub sub sub sub

NOM NOM PROTO NOM ATTRS NOM PROTO ATTRS NOM BLOC NOM PROTO BLOC NOM ATTRS BLOC NOM PROTO ATTRS BLOC

Pour dclarer et dfinir un sous-programme, ajoutez un BLOC :

1. Nous les appellerons aussi fonctions, mais les fonctions sont identiques aux sous-programmes en Perl. Parfois nous les appellerons mme mthodes, qui sont dfinies de la mme faon, mais appeles diffremment.

customer_8566

198

Chapitre 6 Sous-programmes

Pour crer un sous-programme anonyme ou une fermeture, omettez le NOM :


sub sub sub sub

BLOC BLOC ATTRS BLOC PROTO ATTRS BLOC PROTO

PROTO et ATTRS reprsentent le prototype et les attributs, chacun dentre eux tant prsent dans sa propre section plus loin dans ce chapitre. Ils ne sont pas si importants ; le NOM et le BLOC sont les parties essentielles, y compris quand elles sont absentes. Pour les formes sans NOM, vous devez toujours fournir une manire dappeler le sous-programme. Assurez-vous donc de sauvegarder la valeur de retour, car non seulement cette forme de dclaration de sub est compile comme vous pouviez vous y attendre, mais elle fournit galement une valeur de retour lexcution :
$refsub = sub BLOCK;

Pour importer des sous-programmes dfinis dans un autre module, crivez :


use MODULE qw(NOM1 NOM2 NOM3...);

Pour appeler les sous-programmes directement, crivez : NOM(LISTE) NOM LISTE &NOM
# & est optionel avec des parenthses. # Parenthses facultatives si sub prdclare/importe. # Passe le @_ courant ce sous-programme # (et contourne les prototypes).

Pour appeler des sous-programmes de faon indirecte (par leur nom ou par rfrence), utilisez nimporte laquelle de ces formes :
&$refsub(LISTE) $refsub->(LISTE) &$refsub # Le & nest pas facultatif pour un appel indirect # (sauf en utilisant une notation infixe). # Passe le @_ courant ce sous-programme.

Le nom officiel dun sous-programme comprend le prfixe &. Un sous-programme peut tre appel en utilisant le prfixe, mais le & est en gnral optionnel, ainsi que les parenthses si le sous-programme a t prdclar. Cependant, le & nest pas optionnel quand vous ne faites que nommer le sous-programme, comme quand il est utilis comme argument de defined ou undef ou quand vous voulez gnrer une rfrence un sousprogramme nomm en crivant $refsub = \&nom. Le & nest pas non plus optionnel quand vous voulez faire un appel de sous-programme indirect en utilisant lune des constructions &$refsub() ou &{$refsub}(). Cependant, la notation la plus commode $refsub->() nen a pas besoin. Voir le chapitre 8 pour en savoir plus au sujet des rfrences de sous-programmes. Perl nimpose pas de modle particulier dcriture en majuscules ou minuscules pour vos noms de sous-programme. Cependant une convention vaguement suivie est que les fonctions appeles indirectement par Perl lexcution (BEGIN, CHECK, INIT, END, AUTOLOAD, DESTROY et toutes les fonctions mentionnes au chapitre 14, Variables lies) sont toutes en majuscules, aussi vaut-il probablement mieux viter ce style. (Mais les sousprogrammes utiliss pour des valeurs constantes portent dhabitude un nom tout en capitales. Cest normal. Nous esprons...)

customer_8566

Smantique

199

Smantique
Avant de vous mettre dans tous vos tats cause de toute cette syntaxe, souvenez-vous que la manire normale de dfinir un simple sous-programme finit par ressembler cela :
sub guincher { print "Vous voil guinch.\n"; }

et que la manire normale de lappeler est simplement :


guincher();

Dans ce cas, nous avons ignor lentre (les arguments) et la sortie (les valeurs de retour). Mais les modles Perl pour passer des donnes, et depuis un sous-programme, sont vraiment assez simples : tous les paramtres de la fonction sont passs comme une seule liste plat de scalaires, et sil y a plusieurs valeurs de retour, elles sont de mme retournes lappelant comme une seule liste plat de scalaires. Comme pour toute LISTE, les tableaux et les hachages passs dans cette liste sinterpoleront dans la liste plat, perdant par l mme leur identit. Mais il existe plusieurs manires de contourner cela, et linterpolation automatique de liste est souvent trs utile. Les listes de paramtres, comme les listes de retour, peuvent contenir autant (ou aussi peu) dlments que vous voulez (bien que vous puissiez imposer certaines contraintes aux listes de paramtres en utilisant des prototypes). En effet, Perl est conu autour de cette notion de fonctions variadiques (qui peuvent prendre nimporte quel nombre darguments) ; en C, au contraire, elles sont plus ou moins bidouilles contrecur de faon ce que vous puissiez appeler printf(3). Maintenant, si vous voulez un langage conu pour passer un nombre variable darguments arbitraires, vous devriez vous arranger pour quil soit facile de traiter ces listes arbitraires darguments. Tout argument pass un sous-programme Perl est fourni dans le tableau @_. Si vous appelez une fonction avec deux arguments, ils sont accessibles lintrieur de la fonction comme les deux premiers lments de ce tableau : $_[0] et $_[1]. Comme @_ est un tableau ordinaire avec un nom extraordinaire, vous pouvez lui faire tout ce que vous pouvez normalement faire un tableau.2 Le tableau @_ est un tableau local, mais ses valeurs sont des alias des vritables paramtres scalaires. (Cest connu sous le nom de smantique de passage par rfrence.) Vous pouvez donc modifier les vritables paramtres si vous modifiez llment correspondant de @_ (cest cependant rarement fait, tellement il est facile de renvoyer des valeurs intressantes en Perl). La valeur de retour du sous-programme (ou de nimporte quel bloc, en fait) est la valeur de la dernire expression value. Vous pouvez aussi utiliser une instruction return explicite pour spcifier la valeur de retour et sortir du sous-programme depuis nimporte quel point lintrieur. Dans les deux cas, si la fonction est appele en contexte scalaire ou de liste, lexpression finale de cette fonction est appele dans ce mme contexte.

2. Cest un domaine o Perl est plus orthogonal que la plupart des autres langages de programmation.

customer_8566

200

Chapitre 6 Sous-programmes

Trucs avec la liste de paramtres


Perl na pas encore de paramtres formels nomms, mais en pratique tout ce que vous avez besoin de faire, cest de copier les valeurs de @_ dans une liste my, qui sert parfaitement de liste de paramtres formels. (Ce nest pas une concidence si la copie des valeurs change un passage par rfrence en passage par valeur, ce qui est le fonctionnement que les gens attendent habituellement, mme sils ne connaissent pas le vocabulaire de linformatique thorique.) Voici un exemple typique :
sub setenv_peut_etre { my ($cle, $valeur) = @_; $ENV{$cle} = $valeur unless $ENV{$cle}; }

Mais vous ntes pas oblig de nommer vos paramtres, ce qui est tout lintrt du tableau @_. Par exemple, pour calculer un maximum, vous pouvez juste itrer directement sur @_ :
sub max { my $max = shift(@_); for my $element (@_) { $max = $element if $max < $element; } return $max; } $meilleurjour = max($lun,$mar,$mer,$jeu,$ven);

Ou vous pouvez remplir tout un hachage dun coup :


sub configuration { my %options = @_; print "Verbosit maximale.\n" if $options{VERBOSE} == 9; } configuration(PASSWORD => "xyzzy", VERBOSE => 9, SCORE => 0);

Voici un exemple o vos arguments formels ne sont pas nomms afin de pouvoir modifier les arguments eux-mmes :
majuscules_sur_place($v1, $v2); sub majuscules_sur_place { for (@_) { tr/a-z/A-Z/ } } # ceci change $v1 et $v2

Bien sr, vous navez pas le droit de modifier des constantes de cette faon. Si lun des arguments tait en fait un scalaire comme "hobbit" ou une variable en lecture seule comme $1 et que vous essayiez de le modifier, Perl lverait une exception (vraisemblablement fatale et menaant potentiellement votre carrire). Par exemple, ceci ne marchera pas :
majuscules_sur_place("philippe");

Ce serait beaucoup plus sr si la fonction majuscules_sur_place tait crite de faon renvoyer des copies de ses paramtres, au lieu de les modifier directement :

customer_8566

Smantique
($v3, $v4) = majuscules($v1, $v2); sub majuscules { my @parms = @_; for (@parms) { tr/a-z/A-Z/ } # Vrifie si nous avons t appels en contexte de liste. return wantarray ? @parms : $parms[0]; }

201

Remarquez comme cette fonction (sans prototype) se moque de savoir si on lui a pass de vritables scalaires ou des tableaux. Perl aplatira tout dans une grande liste plat de paramtres dans @_. Cest lun des cas o Perl brille par son style simple de passage de paramtres. La fonction majuscules fonctionnera parfaitement bien sans changer sa dfinition, mme si on lui passe des choses comme a :
@nouvelleliste = majuscules(@liste1, @liste2); @nouvelleliste = majuscules( split /:/, $var );

Ne vous laissez cependant pas tenter par cela :


(@a, @b) = majuscules(@liste1, @liste2); # FAUX

Pourquoi ? Parce que, tout comme la liste des paramtres entrants dans @_ est plate, la liste de retour est aussi plat. Ceci stocke donc tout dans @a, et vide @b en y stockant la liste vide. Voir la section Passage de rfrences pour dautres manires de sy prendre.

Indications derreur
Si vous voulez que votre fonction se termine de faon ce que lappelant ralise quune erreur sest produite, la manire la plus naturelle de faire est dutiliser un return simple sans argument. De cette faon, quand la fonction est appele en contexte scalaire, lappelant reoit undef et quand elle utilise en contexte de liste, lappelant reoit une liste vide. Dans des circonstances extraordinaires, vous pourriez choisir de lever une exception pour indiquer une erreur. Utilisez cependant cette mesure avec parcimonie, sinon votre programme va se retrouver envahi de gestionnaires dexception. Par exemple, ne pas russir ouvrir un fichier dans une fonction gnrique douverture de fichier nest pas vraiment un vnement exceptionnel. En revanche ignorer une telle erreur en serait vraiment un. La fonction intgre wantarray retourne undef si votre fonction a t appele en contexte vide ; vous pouvez donc savoir si la valeur de retour de votre fonction est ignore :
if ($quelquechose_a_plante) { return if defined wantarray; # bon, ce nest pas un contexte vide die "Fais attention mon erreur, espce dinconscient !!!\n"; }

Problmes de porte
Les sous-programmes peuvent tre appels de faon rcursive, car chaque appel reoit son propre tableau darguments, mme quand la routine sappelle elle-mme. Si un sous-programme est appel en utilisant la forme &, la liste darguments est optionnelle. Si la forme en & est utilise, mais que la liste darguments est omise, quelque chose de spcial se produit : le tableau @_ de la routine appelante est fourni implicitement. Il

customer_8566

202

Chapitre 6 Sous-programmes

sagit dun mcanisme defficacit que les nouveaux utilisateurs prfreront viter.
&toto(1,2,3); toto(1,2,3); toto(); &toto(); &toto; toto; # passe trois arguments # pareil # passe une liste vide # pareil # # # # toto() reoit les arguments courants, comme toto(@_), mais plus vite ! comme toto() si sub toto est prdclar, sinon le mot simple "toto"

Non seulement la forme & rend la liste darguments optionnelle, mais elle dsactive galement toute vrification de prototypage sur les arguments fournis. Ceci en partie pour des raisons historiques et en partie pour fournir un moyen efficace de tricher si vous savez ce que vous faites. Voir la section Prototypes plus loin dans ce chapitre. Les variables qui sont utilises dans la fonction, mais qui nont pas t dclares prives cette fonction, ne sont pas ncessairement des variables globales ; elles continuent suivre les rgles normales de porte de Perl. Comme expliqu dans la section Noms du chapitre 2, Composants de Perl, cela signifie quelles cherchent dabord tre rsolues dans la ou les portes lexicales englobantes, puis ensuite dans la porte du paquetage. Du point de vue dun sous-programme, toute variable my dune porte lexicale englobante est donc parfaitement visible. Par exemple, la fonction bumpx, ci-dessous, a accs la variable lexicale $x ( porte sur tout le fichier) car la porte dans laquelle ce my a t dclar le fichier lui-mme na pas t ferme avant la dfinition du sous-programme :
# dbut du fichier my $x = 10; # dclare et initialise la variable sub bumpx { $x++ } # la fonction peut voir la variable lexicale externe

Les programmeurs C et C++ verraient probablement $x comme une variable statique de fichier . Elle est prive en ce qui concerne les fonctions dans les autres fichiers, mais globale du point de vue des fonctions dclares aprs le my. Les programmeurs C qui viennent Perl en cherchant ce quils appeleraient des variables statiques pour des fichiers ou des fonctions ne trouvent pas un tel mot-cl. Les programmeurs Perl vitent en gnral le mot statique , parce que les systmes statiques sont morts et ennuyeux et que le mot est trs charg historiquement. Bien que Perl ne dispose pas du mot static dans son dictionnaire, les programmeurs Perl nont aucun problme pour crer des variables qui restent prives une fonction et persistent dun appel de fonction un autre. Cest juste quil nexiste pas de mot spcial pour dcrire cela. Les primitives de porte de Perl sont plus riches et se combinent avec sa gestion automatique de mmoire de telle manire que quelquun cherchant le mot-cl static pourrait ne jamais penser les utiliser. Les variables lexicales ne passent pas automatiquement au ramasse-miettes simplement parce que lon est sorti de leur porte ; elles attendent de ne plus tre utilises pour tre recycles, ce qui est bien plus important. Pour crer des variables prives qui ne sont pas automatiquement rinitialises entre deux appels de fonction, incluez la fonction tout entire dans un bloc supplmentaire et mettez la fois la dclaration my et la dfinition

customer_8566

Passage de rfrences

203

de la fonction lintrieur de ce bloc. Vous pouvez mme y mettre plus dune fonction pour leur donner un accs partag une variable qui, sinon, est prive.
{ my $compteur = 0; sub next_compteur { return ++$compteur } sub prev_compteur { return --$compteur } }

Comme toujours, laccs la variable lexicale est limit au code se trouvant dans la mme porte lexicale. Les noms des deux fonctions sont cependant globalement accessibles ( lintrieur du paquetage) et, comme les fonctions ont t dfinies dans la porte de $compteur, elles peuvent tout de mme accder cette variable bien que personne dautre ne le puisse. Si cette fonction est charge par require ou use, alors cest probablement parfait. Si tout se passe dans le programme principal, vous devrez vous assurer que toute affectation my lexcution est excute suffisament tt, soit en mettant tout le bloc avant votre programme principal, soit en plaant un bloc BEGIN ou INIT autour pour tre sr quil sera excut avant que votre programme ne dmarre :
BEGIN { my @gamme = qw/ do re mi fa sol la si /; my $note = -1; sub ton_suivant { return $gamme[ ($note += 1) %= @gamme ] }; }

Le BEGIN naffecte ni la dfinition du sous-programme, ni la persistence des lexicales utilises par le sous-programme. Il est juste l pour sassurer que les variables sont initialises avant que la routine soit appele. Pour plus dinformation sur la dclaration de variables prives et globales, voir respectivement my et our au chapitre 29, Fonctions. Les constructions BEGIN et INIT sont expliques au chapitre 18, Compilation.

Passage de rfrences
Si vous voulez passer plus dun tableau ou dun hachage, depuis ou vers une fonction, tout en maintenant leur intgrit, vous aurez alors besoin dun mcanisme explicite de passage de rfrences. Avant cela, vous aurez besoin de comprendre les rfrences ainsi quelles sont expliques au chapitre 8. Faute de quoi, cette section risque de ne pas tre trs comprhensible. Enfin, vous pourrez toujours regarder les images... Voici quelques exemples simples. Dfinissons dabord une fonction qui attend une rfrence un tableau. Quand le tableau est grand, il est beaucoup plus rapide de le passer comme une simple rfrence plutt que comme une longue liste de valeurs :
$total = somme ( \@a ); sub somme { my ($reftab) = @_; my ($total) = 0; foreach (@$reftab) { $total += $_ } return $total; }

customer_8566

204

Chapitre 6 Sous-programmes

Passons plusieurs tableaux une fonction, et faisons-la dpiler (via pop) chacun dentre eux, en renvoyant une nouvelle liste de leurs derniers lments :
@derniers = popplus ( \@a, \@b, \@c, \@d ); sub popplus { my @retliste = (); for my $reftab (@_) { push @retliste, pop @$reftab; } return @retliste; }

Voici comment vous pourriez crire une fonction qui ferait une sorte dintersection, en retournant la liste des cls apparaissant dans tous les hachages qui lui sont passs :
@commun = inter( \%toto, \%titi, \%tutu ); sub inter { my %vus; for my $href (@_) { while (my $k = each %$href ) { $vus{$k}++; } } return grep { $vus{$_} == @_ } keys %vus; }

Jusquici nous navons fait quutiliser le mcanisme normal de retour de liste. Que se passe-t-il si vous voulez passer ou renvoyer un hachage ? Sil ne sagit que dun seul ou que cela ne vous gne pas quils soient concatns, les conventions dappel habituelles conviennent, bien quelles soient un peu coteuses. Comme nous lavons expliqu prcdemment, les gens commencent avoir des problmes avec :
(@a, @b) = func(@c, @d);

ou bien :
(%a, %b) = func(%c, %d);

Cette syntaxe ne fonctionne tout simplement pas. Elle se contente de tout affecter @a ou %a tout en vidant @b ou %b. De plus la fonction ne reoit pas deux tableaux ou deux hachages spars : elle reoit une longue liste dans @_, comme toujours. Vous pouvez vous arranger pour que votre fonction prenne des rfrences en paramtre et en renvoie en rsultat. Voici une fonction qui prend deux rfrences de tableau en argument et renvoie les deux rfrences de tableaux ordonnes selon le nombre dlments quils contiennent.
($aref, $bref) = func(\@c, \@d); print "@$aref en a plus que @$bref\n"; sub func { my ($cref, $dref) = @_; if (@$cref > @$dref) { return ($cref, $dref);

customer_8566

Prototypes
} else { return ($dref, $cref); } }

205

Pour passer des handles de fichier ou de rpertoire des fonctions ou si vous voulez quelles en retournent, voir les sections Rfrences de handles et Rfrences de table de symboles au chapitre 8.

Prototypes
Perl vous permet de dfinir vos propres fonctions de faon ce quelles soient appeles comme les fonctions internes de Perl. Considrez la fonction push(@tableau, $element), qui doit tacitement recevoir une rfrence @tableau, et pas seulement les valeurs de la liste contenues dans @tableau, afin que le tableau soit effectivement modifi. Les prototypes vous permettent de dclarer des sous-programmes qui prennent leurs arguments comme beaucoup de fonctions internes, cest--dire avec certaines contraintes au niveau du nombre et du type des arguments. Nous les appelons prototypes mais ils fonctionnent comme des modles automatiques du contexte dappel plutt que de la faon laquelle penseraient des programmeurs C ou Java quand on leur parle de prototypes. Avec ces modles, Perl ajoutera automatiquement des antislashs implicites ou des appels scalar ou ce quil faut pour que les choses se prsentent de manire respecter le modle fourni. Par exemple, si vous dclarez :
sub monpush (\@@);

alors monpush prendra ses arguments exactement comme push les prend. Pour que cela fonctionne, il faut que la dclaration de la fonction soit visible la compilation. Le prototype naffecte linterprtation des appels de fonction que quand le caractre & est omis. En dautres termes, si vous lappelez comme une fonction intgre, elle se comporte comme un fonction intgre. Si vous lappelez comme une bonne vieille routine, elle se comporte comme une bonne vieille routine. Le & supprime les vrifications de prototype et les effets contextuels associs. Comme les prototypes sont pris en considration seulement la compilation, il en dcoule naturellement quils nont aucune inf luence sur les rfrences de sous-programme comme \&toto ou sur les appels de sous-programme indirects comme &{$refsub} ou $refsub->(). Les appels de mthode ne sont pas non plus inf luencs par les prototypes. Cest parce que la vritable fonction appeler est indtermine au moment de la compilation, puisquelle dpend de lhritage, qui est calcul dynamiquement en Perl. Comme il sagit avant tout de permettre de dfinir des sous-programmes qui fonctionnent comme les commandes internes, voici quelques prototypes de fonctions que vous pourriez utiliser pour muler le fonctionnement des fonctions internes correspondantes :
Dclar comme sub monlink ($$) sub monreverse (@) sub monjoin ($@) sub monpop (\@) Appel par monlink $ancien, $nouveau. monreverse $a,$b,$c. monjoin ":",$a,$b,$c. monpop @array.

customer_8566

206
Dclar comme sub monsplice (\@$$@) sub monkeys (\%) sub monpipe (**) sub monindex ($$;$) sub monsyswrite (*$;$$) sub monopen (*;$@) Appel par

Chapitre 6 Sous-programmes

monsplice @tableau,@tableau,0,@pushmoi . monkeys %{$hashref}. monpipe READHANDLE, WRITEHANDLE. monindex &getstring, "substr". monindex &getstring, "substr", $start. monsyswrite OUTF, $buf. monsyswrite OUTF, $buf, length($buf)-$off, $off. monopen HANDLE. monopen HANDLE, $name. monopen HANDLE, "-|", @cmd.

sub mongrep (&@) sub monrand ($) sub montime ()

mongrep { /toto/ } $a,$b,$c. monrand 42. montime.

Tout caractre de prototype prcd dun antislash (entre parenthses dans la colonne de gauche ci-dessus) reprsente un argument rel (dont la colonne de droite donne un exemple) qui doit imprativement commencer par ce caractre. Le premier argument de monkeys doit donc commencer par un %, tout comme le premier argument de keys. Un point-virgule spare les arguments obligatoires des arguments optionnels. (Il serait redondant devant un @ ou un % puisque les listes peuvent tre vides.) Les caractres de prototype sans antislash ont une signification spciale. Tout caractre @ ou % consomme tout le reste des arguments et force un contexte de liste. (Il est quivalent LISTE dans un diagramme de syntaxe.) Un argument reprsent par $force un contexte scalaire. Un & requiert une rfrence un sous-programme nomm ou anonyme. Une * permet au sous-programme daccepter dans cet emplacement tout ce qui serait accept comme un handle de fichier par une fonction interne : un nom simple, une constante, une expression scalaire, un typeglob ou une rfrence un typeglob. Si vous voulez toujours convertir un tel argument en une rfrence de typeglob, utilisez Symbol::qualify_to_ref comme suit :
use Symbol qualify_to_ref; sub toto (*) { my $fh = qualify_to_ref(shift, caller); ... }

Remarquez que les trois derniers exemples dans le tableau sont traits dune manire spciale par lanalyseur. mongrep est analys comme un vritable oprateur de liste, monrand est analys comme un vritable oprateur unaire avec la mme prcdence unaire que rand et montime ne prend vraiment aucun argument, comme time. Cest--dire que si vous crivez :
montime +2;

customer_8566

Prototypes

207

vous aurez montime() + 2 et non montime(2), qui serait le rsultat dune analyse sans prototype ou avec un prototype unaire. Lexemple mongrep illustre aussi comment & est trait spcialement quand il est le premier argument. Dordinaire, un prototype en & ncessiterait un argument comme \&toto ou sub{}. Cependant, quand il est le premier argument, vous pouvez supprimer le sub de votre sous-programme anonyme et simplement passer le bloc simple lemplacement de l objet indirect (sans virgule aprs). Lun des aspects attrayant du prototype & est quil permet de gnrer une nouvelle syntaxe, tant que le & est en premire position :
sub try (&$) { my ($try, $catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch (&) { $_[0] } try { die "phooey"; } # ce nest pas la fin de lappel de fonction ! catch { /phooey/ and print "unphooey\n"; };

Ceci affiche unphooey . Ici, try est appel avec deux arguments, la fonction anonyme {die "phooey";} et la valeur de retour de la fonction catch, qui dans ce cas nest rien dautre que son propre argument, tout le bloc dune autre fonction anonyme. Dans le try, la premire fonction en argument est appele sous la protection dun bloc eval pour intercepter tout ce qui pourrait exploser. Si quelque chose explose effectivement, la seconde fonction est appele avec une version locale de la variable globale $_ contenant lexception qui a t leve.3 Si tout cela est du chinois pour vous, vous allez devoir vous reporter die et eval au chapitre 29, puis vous informer au sujet des fonctions anonymes et des fermetures au chapitre 8. Dun autre ct, si tout cela vous intrigue, vous pouvez jeter un il au module Error sur CPAN, qui utilise cette mthode pour implmenter une gestion dexceptions minutieusement structure avec les clauses try, catch, except, otherwise et finally. Voici une rimplmentation de loprateur grep (loprateur interne est plus efficace, bien sr) :
sub mongrep (&@) { my $coderef = shift;

3. Oui, il reste des questions en suspens par rapport la visibilit de @_. Nous les ignorerons pour le moment. Mais si un jour nous rendons @_ porte lexicale, comme cela se fait actuellement dans les versions exprimentales de Perl avec des threads, ces sous-programmes anonymes pourront se comporter comme des fermetures.

customer_8566

208
my @resultat; foreach $_ (@_) { push(@resultat, $_) if &$coderef; } return @resultat; }

Chapitre 6 Sous-programmes

Certains prfreraient des prototypes compltement alphanumriques. Les caractres alphanumriques ont t intentionnellement laisss en dehors des prototypes dans le but avou dajouter un jour des paramtres formels nomms. (Peut-tre.) Lobjectif majeur du mcanisme actuel est de permettre aux auteurs de modules dimposer un certain nombre de vrifications la compilation aux utilisateurs de leurs modules.

Substitution en ligne de fonctions constantes


Les fonctions prototypes avec (), ce qui signifie quelles ne prennent aucun argument, sont analyses comme la fonction interne time. Mieux, le compilateur traite de telles fonctions comme de bonnes candidates pour la mise en ligne. Si le rsultat de cette fonction, aprs la passe doptimisation et de prcalcul des expressions constantes, est soit une constante, soit un scalaire porte lexicale sans autre rfrence, alors cette valeur sera utilise au lieu des appels la fonction. Les appels faits avec &NOM ne sont cependant jamais mis en ligne, tout comme ils ne sont sujets aucun autre effet de prototype. (Pour une mthode simple de dclaration de telles constantes, voir le pragma use constant au chapitre 31, Modules de pragmas.) Les deux versions de ces fonctions calculant ! seront mises en ligne par le compilateur :
sub pi () sub PI () { 3.14159 } { 4 * atan2(1, 1) } # Pas exact, mais proche # Le mieux quon puisse obtenir

En fait, toutes les fonctions suivantes seront mises en ligne, car Perl peut tout dterminer la compilation :
sub FLAG_TOTO () sub FLAG_TITI () sub FLAG_MASK () { 1 << 8 } { 1 << 9 } { FLAG_TOTO | FLAG_TITI }

sub OPT_BLORGH () { (0x1B58 & FLAG_MASK) == 0 } sub BLORGH_VAL () { if (OPT_BLORGH) { return 23 } else { return 42 } } sub N () { int(BLORGH_VAL) / 3 } BEGIN { # le compilateur excute ce bloc la compilation my $prod = 1; # variable prive, persistante for (1 .. N) { $prod *= $_ } sub NFACT () { $prod } }

Dans le dernier exemple, la fonction NFACT est mise en ligne car elle a un prototype vide et que la variable quelle retourne nest pas modifie par la fonction et ne peut plus ensuite tre modifie par personne, puisquelle est dans une porte lexicale. Le compi-

customer_8566

Prototypes

209

lateur remplace donc toutes les utilisations de NFACT par cette valeur, qui a t prcalcule la compilation grce au BEGIN qui lentoure. Si vous redfinissez un sous-programme qui tait susceptible dtre mis en ligne, vous aurez un avertissement obligatoire. (Vous pouvez vous servir de cet avertissement pour savoir si le compilateur a mis en ligne une routine en particulier.) Lavertissement est considr suffisament important pour ne pas tre optionnel, car les invocations prcdemment compiles de la fonction continueront dutiliser lancienne valeur de la fonction. Si vous voulez redfinir la routine, assurez-vous quelle na pas t mise en ligne en retirant le prototype () (qui change la smantique dappel, aussi faites attention) ou en contrecarrant le mcanisme de mise en ligne dune autre manire, comme par exemple :
sub non_enligne () { return 23 if $$; }

Pour en savoir plus sur ce qui se passe durant les phases de compilation et dexcution de votre programme, voyez le chapitre 18.

Prcautions prendre avec les prototypes


Il vaut probablement mieux rserver les prototypes aux nouvelles fonctions et ne pas les appliquer danciennes fonctions. Ce sont des descripteurs de contexte, pas des protypes du C ANSI, il vous faut donc tre extrmement attentif ne pas imposer silencieusement un contexte diffrent. Supposez par exemple que vous dcidiez quune fonction ne doit prendre quun seul paramtre, comme ceci :
sub func ($) { my $n = shift; print "vous mavez donn $n\n"; }

Cela la transforme en oprateur unaire (comme loprateur interne rand) et modifie la faon dont le compilateur dtermine les arguments de la fonction. Avec le nouveau prototype, la fonction consomme un seul argument en contexte scalaire, au lieu de plusieurs arguments en contexte de liste. Si quelquun la appele avec un tableau ou une expression de liste, mme si ce tableau ou cette liste ne contenait quun seul lment, l o cela marchait vous aurez maintenant quelque chose de compltement diffrent :
func @toto; func split /:/; func "a", "b", "c"; func("a", "b", "c"); # # # # # compte les lments de @toto compte le nombre dlments retourns passe "a" seulement, le jette avec "b" et retourne "c" soudain, une erreur du compilateur !

Vous venez juste de fournir un scalar implicite devant la liste darguments, ce qui peut tre trs surprenant. Ce nest pas le vieux @toto qui contenait une seule valeur qui est pass. la place, cest 1 (le nombre dlments de @toto) qui est maintenant pass func. Le split, tant appel en contexte scalaire, scribouille partout dans votre liste de paramtres @_. Dans le troisime exemple, comme func a t prototype comme un oprateur unaire, seul a lui est pass ; puis la valeur de retour de func est jete tandis que loprateur virgule value les deux lments suivants et retourne c . Dans le dernier exemple, lutilisateur obtient maintenant une erreur de syntaxe la compilation,

customer_8566

210

Chapitre 6 Sous-programmes

sur du code qui compilait et fonctionnait parfaitement. Si vous crivez du nouveau code et que vous voudriez un oprateur unaire qui ne prend quune variable scalaire, et pas une expression scalaire, vous pouvez toujours le prototyper pour quil prenne une rfrence un scalaire :
sub func (\$) { my $nref = shift; print "vous mavez donn $$nref\n"; }

Maintenant le compilateur ne laissera rien passer qui ne commence pas par un dollar :
func func func func func func @toto; split/:/; $s; $a[3]; $h{bazar}[-1]; 2+5; # # # # # # # # # erreur de compilation, voit @, veut $ erreur de compilation, voit une fonction, veut $ celui-ci va bien ; on a eu un vrai $ celui-ci aussi et mme a expression scalaire, toujours une erreur de compilation a marche, mais le remde nest-il pas pire que le mal ?

func ${ \(2+5) };

Si vous ne faites pas attention, vous pouvez vous attirer des ennuis avec les prototypes. Mais si vous faites attention, vous pouvez faire tout un tas de trucs classe avec. Tout cela est bien sr trs puissant, et ne devrait tre utilis quavec modration pour rendre le monde meilleur.

Attributs de sous-programmes
Une dclaration ou une dfinition de sous-programme peut se voir associer une liste dattributs. Si une telle liste dattributs est prsente, elle sera dcoupe en fonction des blancs ou des deux-points et traite comme si un use attributes avait t vu. Voir le pragma use attributes au chapitre 31 pour des dtails internes. Il existe trois attributs standards pour les sous-programmes : locked, method et lvalue.

Les attibuts locked et method


# Un seul thread est autoris dans cette fonction. sub afunc : locked { ... } # Un seul thread est autoris dans cette fonction pour un objet donn. sub afunc : locked method { ... }

Mettre lattribut locked na de sens que lorsque la fonction ou la mthode est suppose tre appele par plusieurs threads simultanment. Quand il est appliqu une fonction qui nest pas une mthode, Perl sassure quun verrou est mis sur la routine elle-mme avant que lon ny entre. Quand il est appliqu une fonction qui est une mthode (cest--dire une fonction galement marque avec lattribut method), Perl sassure que toute invocation de cette mthode verrouille implicitement son premier argument (lobjet) avant lexcution.

customer_8566

Attributs de sous-programmes

211

La smantique de ce verrou est la mme quen utilisant loprateur lock dans un sousprogramme en premire instruction de ce sous-programme. Pour en savoir plus sur les verrous, voir le chapitre 17, Threads. Lattribut method peut tre utilis tout seul :
sub afunc : method { ... }

lheure actuelle, cela na pour seul effet que de marquer la routine de faon ne pas dclencher lavertissement Ambiguous call resolved as CORE::%s . (Nous pourrons lui donner une signification plus importante un de ces jours.) Le systme dattributs est extensible par lutilisateur, ce qui vous permet de crer vos propres noms dattribut. Ces nouveaux attributs doivent porter des noms didentificateur valides (sans autre caractre de ponctuation que _ ). Une liste de paramtres peut y tre ajoute, pour laquelle nest vrifie pour le moment que le bon quilibrage des parenthses. Voici des exemples de syntaxe valide (bien que les attributs soient inconnus) :
sub fnord (&\%) : switch(10,foo(7,3)) : expensive; sub plugh () : Ugly(\(") :Bad; sub xyzzy : _5x5 { ... }

Voici des exemples de syntaxe incorrecte :


sub sub sub sub fnord snoid xyzzy plugh : : : : switch(10,toto(); Laid((); 5x5; Y2::nord; # # # # # # chane () dsquilibre chane () dsquilibre "5x5" nest pas un identificateur valide "Y2::nord" nest pas un identificateur simple "+" nest ni un espace ni un deux-points

sub snurt : toto + titi;

La liste dattributs est passe comme une liste de chanes constantes au code qui les associe avec le sous-programme. La faon exacte dont cela fonctionne (ou ne fonctionne pas) est hautement exprimentale. Pour des dtails actuels sur les listes dattributs et leur manipulation, voir attributes(3).

Lattribut lvalue
Il est possible de renvoyer un scalaire modifiable depuis un sous-programme, mais seulement si vous dclarez que le sous-programme retourne une lvalue :
my $val; sub modifiable : lvalue { $val; } sub nonmodifiable { $val; } modifiable() = 5; nonmodifiable() = 5; # Affecte $valeur. # ERREUR

Si vous passez des paramtres un sous-programme lvalu, vous aurez besoin de parenthses pour lever lambigut sur ce qui est affect :

customer_8566

212
modifiable $x modifiable 42 modifiable($x) modifiable(42) = 5; = 5; = 5; = 5; # # # # #

Chapitre 6 Sous-programmes
affecte 5 $x avant ! impossible de modifier une constante : erreur de compilation ceci fonctionne et cela aussi

Si vous voulez finasser, vous pouvez contourner cela dans le cas particulier dune fonction ne prenant quun seul argument. Dclarer la fonction avec le prototype ($) la fait analyser avec la prcdence dun oprateur unaire nomm. Comme les oprateurs unaires nomms ont une prcdence suprieure celle de laffectation, vous navez plus besoin de parenthses. (La question de savoir si cela est souhaitable ou pas est laisse lapprciation de la milice du style.) En revanche, vous navez pas besoin de finasser dans le cas dun sous-programme qui ne prend aucun argument (cest--dire avec un prototype ()). Vous pouvez sans ambigut crire :
modifiable = 5;

Cela fonctionne car aucun terme valide ne commence par =. De mme, vous pouvez omettre les parenthses dans les appels de mthodes lvalues quand vous ne passez aucun argument :
$obj->modifiable = 5;

Nous promettons de ne pas casser ces deux constructions dans les prochaines versions de Perl. Elles sont pratiques quand vous voulez encapsuler des attributs dobjet dans des appels de mthodes (de faon ce quils soient hrits comme des appels de mthodes, mais accessibles comme des variables). Le contexte scalaire ou de liste du sous-programme avec lattribut lvalue et de la partie droite dune affectation ce sous-programme est dans les deux cas dtermin en remplaant lappel de fonction par un scalaire. Considrez par exemple :
data(2,3) = get_data(3,4);

Les deux sous-programmes ont t appels en contexte scalaire, tandis que dans :
(data(2,3)) = get_data(3,4);

et dans :
(data(2),data(3)) = get_data(3,4);

tous les sous-programmes sont appels en contexte de liste. Limplmentation actuelle ne permet pas des tableaux ou des hachages dtre retourns directement par des sous-programme lvalus. Vous pouvez toujours renvoyer une rfrence la place.

customer_8566

Formats

Perl dispose dun mcanisme pour vous aider gnrer des rapports et des tableaux simples. Ainsi, Perl vous aide coder votre page de sortie dune faon proche de ce quoi elle ressemblera quand elle saffichera. Il garde trace du nombre de lignes sur la page, du numro de page courant, de quand imprimer les en-ttes de page et ainsi de suite. Les mots-cls sont emprunts FORTRAN : format pour les dclarer et write pour les excuter. Voir les sections correspondantes au chapitre 29, Fonctions. Heureusement la disposition est beaucoup plus lisible, plus proche du PRINT USING de BASIC. Vous pouvez le voir comme le nroff(1) du pauvre. (Si vous connaissez nroff, a ne ressemble peuttre pas un encouragement.) Les formats, comme les paquetages et les sous-programmes, sont dclars plutt quexcuts, et peuvent donc apparatre nimporte o dans votre programme. (Bien quen gnral il vaille mieux les regrouper tous ensemble.) Ils ont leur propre espace de nommage diffrent de ceux de tous les autres types de Perl. Cela signifie que si vous avez une fonction nomme toto , elle na rien voir avec le format nomm toto . Cependant le nom par dfaut du format associ un handle de fichier donn est le mme que le nom de ce handle. Le format par dfaut de STDOUT est donc nomm STDOUT , et le format par dfaut du handle de fichier TEMP est galement appel TEMP . Ils ont lair identiques. Mais ils ne le sont pas. Les formats denregistrement de sortie sont dclars de la manire suivante :
format NOM = FORMLISTE .

If NOM est omis, cest le format STDOUT qui est dfini. FORMLISTE est compose dune srie de lignes, chacun pouvant tre de trois types : un commentaire, indiqu par une # en premire colonne ; une ligne image , donnant le format pour une ligne de sortie ; une ligne darguments fournissant les valeurs insrer dans la ligne dimage prcdente.

customer_8566

214

Chapitre 7 Formats

Les lignes images sont imprimes exactement comme elles apparaissent hormis certains champs auxquels sont substitues des valeurs.1 Chaque champ de substitution dans une ligne image commence, soit par un signe @, soit par un ^. Ces lignes ne subissent aucune forme dinterpolation de variable. Le champ @ ( ne pas confondre avec le marqueur de tableau @) reprsente le type normal de champ ; lautre type, ^, est utilis pour un remplissage rudimentaire de blocs de texte multilignes. La longueur du champ est indique en remplissant le champ avec plusieurs caractres <, > ou | pour indiquer respectivement la justification gauche, droite ou au centre. Si la variable excde la longueur spcifie, elle est tronque. Vous pouvez galement utiliser, comme autre forme de justification droite, des caractres # (aprs un caractre @ ou ^ initial) pour spcifier un champ numrique. Vous pouvez insrer un . la place de lun des caractres # pour aligner les points dcimaux. Si lune des valeurs fournies pour ces champs contient un saut de ligne, seul le texte avant ce saut de ligne est imprim. Enfin, le champ spcial @* peut tre utilis pour imprimer des valeurs multilignes de manire non tronque ; il devrait gnralement apparatre seul sur une ligne image. Les valeurs sont spcifies sur la ligne suivante dans le mme ordre que les champs images. Les expressions fournissant les valeurs doivent tre spares par des virgules. Les expressions sont toutes values en contexte de liste avant que la ligne ne soit traite, et une seule expression peut donc produire plusieurs lments de liste. Les expressions peuvent stendre sur plusieurs lignes, si elles sont mises entre accolades. (Dans ce cas, laccolade ouvrante doit tre le premier token sur la premire ligne.) Cela vous permet daligner les valeurs sous leurs champs de format respectifs pour faciliter la lecture. Si lvaluation dune expression donne un nombre avec une partie dcimale, et si limage correspondante spcifie que la partie dcimale doit apparatre dans la sortie (cest-dire nimporte quelle image sauf une srie de # sans . inclus), le caractre pour le point dcimal est toujours dtermin par la valeur de la locale LC_NUMERIC. Cela signifie que si lenvironnement dexcution spcifie par exemple une locale franaise, une virgule sera utilise plutt quun point. Pour plus dinformation, voir la page de manuel perllocale. lintrieur dune expression, les caractres blancs \n, \t et \f sont tous considrs comme quivalents un espace seul. Vous pourriez voir cela comme si le filtre suivant tait appliqu chaque valeur dans le format :
$valeur =~ tr/\n\t\f/ /;

Le caractre blanc restant, \r, force laffichage dune nouvelle ligne si la ligne image le permet. Les champs images qui commencent par ^ plutt que @ sont traits de manire spciale. Avec un champ #, celui-ci est vide si la valeur est indfinie. Pour les autres types de champ, le chapeau permet un genre de mode de remplissage. Au lieu dune expression arbitraire, la valeur fournie doit tre un nom de variable scalaire contenant une chane
1. Mme ces champs conservent lintgrit des colonnes o vous les mettez. Il ny a rien dans une ligne image qui peut faire crotre ou rtrcir ou se dcaler un champ. Les colonnes que vous voyez sont sacres au sens WYSIWYG (si vous utilisez une fonte chasse fixe). Mme les caractres de contrle sont supposs avoir une largeur de un.

customer_8566

Formats

215

de caractres. Perl met tout le texte quil peut dans le champ, puis coupe le dbut de la chane de faon ce que la fois suivante o la variable est rfrence le reste du texte puisse tre imprim. (Oui, cela signifie que le contenu de la variable est altr pendant lexcution de lappel write et nest pas prserv. Utilisez une variable temporaire si vous voulez prserver la valeur originale.) Normalement, vous devrez utiliser une squence de champs aligns verticalement pour afficher un bloc de texte. Vous pouvez terminer le champ final par le texte ... , qui apparatra dans la sortie seulement si le texte tait trop long pour tre affich entirement. Vous pouvez modifier les caractres de rupture en modifiant la valeur de la variable $: ($FORMAT_LINE_BREAK_CHARACTERS si vous utilisez le module English) en une liste des caractres dsirs. Les champs ^ peuvent produire des enregistrements de longueur variable. Si le texte formater est court, rptez quelques fois la ligne de format avec le champ ^. Si vous faites cela pour de courtes donnes, vous obtiendrez quelques lignes blanches. Pour supprimer les lignes qui finiraient blanches, mettez un caractre ~ (tilde) nimporte o sur la ligne. (Le tilde lui-mme est transform en espace la sortie.) Si vous mettez un second tilde la suite du premier, la ligne sera rpte jusqu ce que tout le texte des champs de cette ligne ait t affich. (Cela fonctionne car tous les champs ^ avalent les chanes quils impriment. Mais si vous utilisez un champ de type @ en conjonction avec deux tildes, vous avez intrt ce que lexpression fournie ne renvoie pas perptuellement la mme valeur ! Utilisez un shift ou un autre oprateur dont lun des effets secondaires puise toutes les valeurs.) Le traitement des en-ttes de format est gr par dfaut par un format de mme nom que le handle de fichier courant, auquel _TOP a t concatn. Il est dclench au dbut de chaque page. Voir write au chapitre 29. Voici quelques exemples :
# un rapport sur le fichier /etc/passwd format STDOUT_TOP = Fichier Passwd Nom Login Bureau Uid Gid Home -----------------------------------------------------------------. format STDOUT = @<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<< $nom, $login, $bureau,$uid,$gid, $home . # un rapport partir dun formulaire de rapport de bogues format STDOUT_TOP = Rapport de bogues @<<<<<<<<<<<<<<<<<<<<<<< @||| @>>>>>>>>>>>>>>>>>>>>>>> $systeme, $%, $date -----------------------------------------------------------------. format STDOUT = Sujet: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $suject

customer_8566

216

Chapitre 7 Formats

Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $index, $description Priorit: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $priorite, $date, $description De: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $de, $description Assign : @<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $programmeur, $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<... $description .

Les variables lexicales ne sont pas visibles dans un format sauf si le format est dclar dans la porte de la variable lexicale. Il est possible de mlanger des appels print et write sur le mme canal de sortie, mais il vous faudra grer la variable spciale $- ($FORMAT_LINES_LEFT si vous utilisez le module English) vous-mme.

Variables de format
Le nom de format en cours est stock dans la variable $~ ($FORMAT_NAME), et le nom de len-tte de format en cours dans $^ ($FORMAT_TOP_NAME). Le numro de page de sortie courant est stock dans $% ($FORMAT_PAGE_NUMBER), et le nombre de lignes dans la page se trouve dans $= ($FORMAT_LINES_PER_PAGE). Le vidage automatique du tampon de sortie de ce handle est positionn dans $| ($OUTPUT_AUTOFLUSH). La chane sortie avant chaque en-tte de page est stocke dans $^L ($FORMAT_FORMFEED). Ces variables sont positionnes pour chaque handle de fichier, aussi devrez-vous faire un select sur le handle de fichier associ un format pour modifier ses variables de format :
select((select(OUTF), $~ = "Mon_Autre_Format", $^ = "Mon_Entete_de_Format" )[0]);

Cest bien moche, hein ? Cest cependant un idiome commun, aussi ne soyez pas trop surpris en le voyant. Vous pouvez au moins utiliser une variable temporaire pour conserver le handle de fichier prcdent :
$ofh = select(OUTF); $~ = "Mon_Autre_Format"; $^ = "Mon_Entete_de_Format"; select($ofh);

customer_8566

Variables de format

217

Non seulement cest une meilleure approche en gnral, car cela amliore la lisibilit du code, mais vous avez maintenant en plus une instruction intermdiaire o sarrter dans le code avec un debogueur en pas pas. Si vous utilisez le module English, vous pouvez mme lire le nom des variables :
use English; $ofh = select(OUTF); $FORMAT_NAME = "Mon_Autre_Format"; $FORMAT_TOP_NAME = "Mon_Entete_de_Format"; select($ofh);

Mais il vous reste quand mme ces appels bizarres select. Si vous voulez les viter, utilisez le module FileHandle fourni avec Perl. Maintenant vous pouvez accder ces variables spciales en utilisant des noms de mthodes en minuscules la place :
use FileHandle; OUTF->format_name("Mon_Autre_Format"); OUTF->format_top_name("Mon_Entete_de_Format");

Cest quand mme mieux ! Comme la ligne de valeurs qui suit votre ligne image peut contenir des expressions arbitraires (pour les champs @, pas pour les champs ^), vous pouvez passer les traitements plus compliqus dautres fonctions, comme printf ou une de vos propres fonctions. Par exemple pour insrer des virgules dans un nombre :
format Ident = @<<<<<<<<<<<<<<< commify($n) .

Pour afficher un vrai @, ~ ou ^ dans un champ, faites comme ceci :


format Ident = Jai un @ ici. "@" .

Pour centrer tout une ligne de texte, faites quelque chose comme cela :
format Ident = @|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "Une ligne de texte" .

Lindicateur de longueur de champ > garantit que le texte sera justifi droite dans le champ, mais le champ lui-mme se place exactement o vous lavez plac. Il nexiste pas de manire intgre de dire mets ce champ droite de la page, quelle que soit sa largeur . Vous devez spcifier o il se trouve relativement la marge de gauche. Ceux qui sont vraiment dsesprs peuvent gnrer leur propre format au vol, en sappuyant sur le nombre courant de colonnes (non fourni) et puis faire un eval :
$format = . . . . "format STDOUT = \n" ^ . < x $cols . "\n" $entry . "\n" "\t^" . "<" x ($cols-8) . "~~\n" $entry . "\n"

customer_8566

218
. ".\n"; print $format if $Debug; eval $format; die $@ if $@;

Chapitre 7 Formats

La ligne la plus importante est probablement celle du print. Ce quil imprime ressemble ceci :
format STDOUT = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $entry ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~ $entry .

Voici un petit programme qui se comporte comme lutilitaire Unix fmt(1) :


format = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ $_ . $/ = ""; while (<>) { s/\s*\n\s*/ /g; write; }

Pieds de page
Alors que $^ ($FORMAT_TOP_NAME) contient le nom du format den-tte courant, il nexiste pas de mcanisme correspondant pour les pieds de page. Lun des problmes majeurs est de ne pas savoir quelle sera la taille dun format avant de lavoir valu. Cest dans la liste des choses faire.2 Voici une stratgie : si vous avez un pied de page de taille fixe, vous pouvez lafficher en vrifiant $- ($FORMAT_LINES_LEFT) avant chaque write puis afficher le pied de page si ncessaire. Voici une autre stratgie : ouvrez un tube sur vous-mme, en utilisant open(MOIMEME, "|-") (voir lentre open au chapitre 29) et faites toujours des write sur MOIMEME au lieu de STDOUT. Le processus fils devra traiter son STDIN aprs coup pour rarranger ses enttes et pieds de page votre guise. Pas trs pratique, mais faisable.

2. Bien sr, cela ne garantit en rien que ce sera fait un jour. Les formats sont quelque chose dun peu dpass en cet ge du WWW, de lUnicode, du XML, du XSLT et toutes les autres choses quon inventera aprs tout a.

customer_8566

Pieds de page

219

Accs au mcanisme interne de formatage


Pour accder au mcanisme interne de formatage, vous pouvez utiliser loprateur intgr formline et accder $^A (la variable $ACCUMULATOR) directement. Par exemple :
$str = formline <<END, 1,2,3; @<<< @||| @>>> END print "Wouah, je viens juste de mettre `$^A dans laccumulateur !\n";

Ou pour crer un sous-programme swrite qui serait write ce que sprintf est printf :
use Carp; sub swrite { croak "usage: swrite IMAGE ARGS" unless @_; my $format = shift; $^A = ""; formline($format, @_); return $^A; } $chaine = swrite(<<END, 1, 2, 3); Vrifiez-moi @<<< @||| @>>> END print $chaine;

Si vous utilisiez le module FileHandle, vous pourriez utiliser formline comme suit pour passer la ligne la colonne 72 :
use FileHandle; STDOUT->formline("^" . ("<" x 72) . "~~\n", $long_texte);

customer_8566

customer_8566

Rfrences

Pour des raisons tant philosophiques que pratiques, Perl a toujours favoris les structures de donnes plates et linaires. Et pour beaucoup de problmes, cest exactement ce dont vous avez besoin. Imaginez que vous vouliez construire une table simple (un tableau deux dimensions) listant certaines informations anthropomtriques ge, couleur des yeux, poids concernant un groupe de personnes. Vous pourriez faire cela en crant un tableau pour chaque individu :
@john = (47, "marron", 84); @mary = (23, "noisette", 58); @bill = (35, "bleu", 71);

Vous pourriez ensuite construire un simple tableau supplmentaire contenant les noms des autres tableaux :
@infos = (john, mary, bill);

Pour changer la couleur des yeux de John en rouge aprs une vire en ville, il nous faut un moyen de changer le contenu de @john partir de la simple chane john . Cest le problme classique des indirections, que diffrents langages rsolvent de diffrentes manires. En C, la forme la plus courante dindirection est le pointeur, qui permet une variable de contenir ladresse en mmoire dune autre variable. En Perl, la forme la plus courante dindirection est la rfrence.

Quest-ce quune rfrence ?


Dans notre exemple, $infos[0] contient la valeur john . Cest--dire quil contient une chane qui se trouve tre le nom dune autre variable (globale). On dit que la premire variable se rfre la seconde ; cette sorte de rfrence est appele symbolique, puisque Perl doit rechercher @john dans une table de symboles pour le retrouver. (Vous pouvez voir les rfrences symboliques comme analogues aux liens symboliques dun systme de fichiers.) Nous parlerons des rfrences symboliques un peu plus loin dans ce chapitre.

customer_8566

222

Chapitre 8 Rfrences

Lautre type de rfrences sont les rfrences en dur (hard references), qui constituent ce que les programmeurs Perl utilisent le plus souvent pour accomplir leurs indirections (quand ce ne sont pas leurs indiscrtions). Nous les appelons rfrences en dur non pas parce quelles sont compliques, mais parce quelles sont relles et solides. Si vous prfrez, vous pouvez voir les rfrences en dur comme de vraies rfrences et les rfrences symboliques comme de fausses rfrences. Cest un peu comme la diffrence entre avoir des amis et avoir des relations. Quand nous ne prcisons pas de quel type de rfrence nous parlons, il sagit de rfrences en dur. La figure 8-1 prsente une variable nomme $titi faisant rfrence au contenu dune variable nomme $toto qui a la valeur robot .

Figure 8-1. Une rfrence en dur et une rfrence symbolique Contrairement aux rfrences symboliques, une vraie rfrence ne se rfre non pas au nom dune autre variable (qui nest que le conteneur dune valeur), mais la valeur ellemme, un bout de donne interne. Il ny a pas de mot pour dcrire cela, mais quand il le faut nous lappellerons le rfrent. Supposez par exemple que vous crez une rfrence en dur vers le tableau porte lexicale @tableau. Cette rfrence en dur, et le rfrent auquel elle se rfre, continueront dexister mme quand @tableau sera hors de porte. Un rfrent nest dtruit que quand toutes les rfrences qui pointent sur lui ont t limines. Un rfrent na pas vraiment de nom propre, en dehors des rfrences qui sy rfrent. Pour le dire dune autre faon, chaque variable Perl vit dans une sorte de table de symboles, qui contient une rfrence vers le rfrent sous-jacent (qui lui na pas de nom). Le rfrent peut tre simple, comme un nombre ou une chane, ou complexe, comme un tableau ou un hachage. Dans tous les cas, il y a toujours exactement une rfrence de la variable sa valeur. Vous pouvez ventuellement crer de nouvelles rfrences en dur vers le mme rfrent, mais si vous le faites, la variable elle-mme nen sait rien (et sen moque).1 Une rfrence symbolique est juste une chane qui se trouve tre le nom de quelque chose dans la table des symboles. Ce nest pas tellement un type distinct, mais plutt quelque chose que vous faites avec une chane. Alors quune rfrence en dur est une crature compltement diffrente. Cest le troisime des trois types scalaires fondamentaux, les deux autres tant les chanes et les nombres. Une rfrence en dur na pas be-

1. Si vous tes curieux, vous pouvez vous servir du module Devel::Peek, fourni avec Perl, pour dterminer la valeur du compteur de rfrences sous-jacent.

customer_8566

Cration de rfrences

223

soin de connatre le nom de quelque chose pour pointer dessus, et en fait il est compltement normal quil ny ait pas de nom utiliser du tout. De tels rfrents sans nom du tout sont anonymes ; nous en parlons dans la partie Donnes anonymes ci-dessous. Rfrencer une valeur, dans la terminologie de ce chapitre, consiste crer une rfrence en dur vers elle. (Il existe un oprateur spcial pour cette action cratrice.) La rfrence ainsi cre est un simple scalaire, qui se comporte dans les situations usuelles comme nimporte quel autre scalaire. Drfrencer ce scalaire signifie utiliser la rfrence pour obtenir le rfrent. Le rfrencement et le drfrencement se produisent quand vous invoquez des mcanismes explicites ; il ne se produit jamais de rfrencement ou de drfrencement implicites en Perl. Enfin, presque jamais. Un appel de fonction peut passer implicitement des rfrences si elle a un prototype qui la dclare ainsi. Dans ce cas, lappelant de la fonction ne passe pas explicitement une rfrence, bien quil vous faille toujours drfrencer explicitement celle-ci lintrieur de la fonction. Voir la section Prototypes au chapitre 6, Sous-programmes. Et pour tre totalement honnte, il se produit aussi des drfrencements en coulisses quand vous utilisez certains types de handles de fichiers. Mais cela relve de la compatibilit antrieure et reste transparent pour lutilisateur lambda. Finalement, deux fonctions internes, bless et lock, prennent toutes deux une rfrence en argument mais la drfrencent implicitement pour faire leurs manipulations sur ce qui se cache derrire. Ces indiscrtions admises, le principe selon lequel Perl na pas envie de toucher vos niveaux dindirections tient toujours. Une rfrence peut pointer sur nimporte quelle structure de donnes. Comme les rfrences sont des scalaires, vous pouvez les stocker dans des tableaux et des hachages, et ainsi construire des tableaux de tableaux, des tableaux de hachages, des hachages de tableaux, des tableaux de hachages de fonctions, et ainsi de suite. Vous trouverez des exemples de cela dans le chapitre 9, Structures de donnes. Gardez cependant lesprit que les tableaux et les hachages de Perl sont une dimension en interne. Cest--dire que leurs lments ne peuvent contenir que des valeurs scalaires (chanes, nombres et rfrences). Quand nous disons quelque chose comme tableau de tableaux , nous pensons en fait tableau de rfrences des tableaux , tout comme nous pensons hachage de rfrences des fonctions quand nous disons hachage de fonctions . Mais comme les rfrences sont la seule faon dimplmenter de telles structures en Perl, il sensuit que lexpression plus courte et moins prcise nest tout de mme pas fausse, et ne devrait donc pas tre totalement dnigre, moins que vous ne soyez maniaque.

Cration de rfrences
Il existe plusieurs faons de crer des rfrences, dont nous dcrirons la plupart avant dexpliquer comment utiliser (drfrencer) les rfrences rsultantes.

Loprateur antislash
Vous pouvez crer une rfrence une variable nomme ou un sous-programme grce un antislash. (Vous pouvez aussi vous en servir sur une valeur scalaire anonymes

customer_8566

224

Chapitre 8 Rfrences

comme 7 ou "chameau", bien que cela soit rarement ncessaire.) Cet oprateur fonctionne comme loprateur & (adresse de) en C du moins premire vue. Voici quelques exemples :
$refscalaire $refconst $reftableau $refhash $refcode $refglob = = = = = = \$toto; \186_282.42; \@ARGV; \%ENV; \&handler; \*STDOUT;

Loprateur antislash peut faire bien plus que de crer de simples rfrences. Il crera toute une liste de rfrences sil est appliqu une liste. Pour plus de dtails, voir la section Dautres tours avec les rfrences en dur.

Donnes anonymes
Dans les exemples que nous venons de vous montrer, loprateur antislash se contente de dupliquer une rfrence qui est dj contenue dans un nom de variable avec une exception. Le 186_282.42 nest rfrenc par aucune variable cest juste une valeur. Cest lun de ces rfrents anonymes que nous avons mentionns prcdemment. On ne peut accder aux rfrents anonymes qu travers des rfrences. Celui-ci est un nombre, mais vous pouvez aussi bien crer des tableaux anonymes, des hachages anonymes et des sous-programmes anonymes.

Le composeur de tableaux anonymes


Vous pouvez crer une rfrence un tableau anonyme en employant des crochets :
$reftableau = [1, 2, [a, b, c, d]];

Ici nous avons construit un tableau anonyme de trois lments, dont le dernier lment est une rfrence un tableau anonyme quatre lments (dcrit la figure 8-2). (La syntaxe multidimensionnelle dcrite plus loin peut tre utilise pour y accder. Par exemple, $reftableau->[2][1] aurait la valeur b .)

Figure 8-2. Une rfrence un tableau, dont le troisime lment est lui-mme une rfrence de tableau Nous avons maintenant une mthode pour reprsenter la table du dbut de ce chapitre :

customer_8566

Cration de rfrences
$table = [ [ "john", 47, "marron", 84], [ "mary", 23, "noisette", 58], [ "bill", 35, "bleu", 71] ];

225

Les crochets fonctionnent de cette faon seulement quand lanalyseur de Perl attend un terme dans une expression. Ils ne doivent pas tre confondus avec les crochets dans une expression comme $tableau[6] bien que lassociation mnmotechnique avec les tableaux soit volontaire. lintrieur dune chane entre guillemets, les crochets ne provoquent pas la cration de tableaux anonymes ; ils deviennent simplement des caractres littraux dans la chane. (Les crochets fonctionnent toujours pour lindexation lintrieur de chanes, sinon vous ne pourriez pas afficher des valeurs comme "VAL=$tableau[6]\n". Et pour tre tout fait honnte, vous pouvez en fait glisser des composeurs de tableaux anonymes dans une chane, mais seulement sils sont inclus dans une expression plus grande qui est interpole. Nous parlerons de cette fonctionnalit sympathique un peu plus loin dans ce chapitre, car elle implique du drfrencement aussi bien que du rfrencement.)

Le composeur de hachages anonymes


Vous pouvez crer une rfrence un hachage anonyme avec des accolades :
$hashref = { Adam => Eve, Clyde => $bonnie, Antoine => Clo . patre, };

Vous pouvez librement mlanger les composeurs dautres tableaux, hachages ou sousprogrammes anonymes pour les valeurs (mais pas pour les cls) afin de construire une structure aussi complique que vous le souhaitez. Nous avons maintenant une nouvelle manire de reprsenter la table du dbut de ce chapitre :
$table = { "john" => [ 47, "marron", 84 ], "mary" => [ 23, "noisette", 58 ], "bill" => [ 35, "bleu", 71 ], };

Cest un hachage de tableaux. Le choix de la meilleure structure est une affaire dlicate, et le prochain chapitre y est entirement ddi. Mais pour vous faire saliver, nous pouvons mme utiliser un hachage de hachages pour notre table :
$table = { "john" => { age => 47, yeux => "marron", poids => 84, }, "mary" => { age => 23, yeux => "noisette", poids => 58, },

customer_8566

226
"bill" => { age => 35, yeux => "bleu", poids => 71, }, };

Chapitre 8 Rfrences

Comme avec les crochets, les accolades fonctionnent de cette faon uniquement quand Perl attend un terme dans une expression. Il ne faut pas les confondre avec les accolades dans une expression comme $hash{cle} bien que lassociation mnmotechnique soit (encore) volontaire. Les mmes avertissements sappliquent quant lutilisation des accolades lintrieur dune chane. Voici un avertissement supplmentaire qui ne sappliquait pas aux crochets. Comme les accolades sont aussi utilises pour plusieurs autres choses (y compris les blocs), vous pourrez occasionnellement avoir besoin de distinguer les accolades au dbut dune instruction en mettant un + ou un return devant, afin que Perl ralise que ce nest pas un bloc qui commence. Par exemple, si vous voulez une fonction qui cre un nouveau hachage et renvoie une rfrence sur lui, vous avez les possibilits suivantes :
sub hacheles { { @_ } } sub hacheles { +{ @_ } } sub hacheles { return { @_ } } # Silencieusement FAUX -- renvoie @_. # Ok. # Ok.

Le composeur de sous-programmes anonymes


Vous pouvez crer une rfrence un sous-programme anonyme en utilisant sub sans nom de sous-programme :
$refcode = sub { print "Boink!\n" }; "Boink!" # Maintenant &$refcode affiche

Remarquez la prsence du point-virgule, qui est obligatoire pour terminer lexpression. (Il ne le serait pas aprs la dclaration usuelle subNOM{} qui dclare et dfinit un sousprogramme nomm.) Hormis le fait que le code lintrieur nest pas excut immdiatement, un sub {} sans nom est plus un oprateur quune dclaration comme do {} ou eval {}. Il se contente de gnrer une rfrence au code, qui dans notre exemple est stocke dans $refcode. Cependant, quel que soit le nombre de fois que vous excutez la ligne ci-dessus, $refcode se rfrera toujours au mme sous-programme anonyme.2

Constructeurs dobjets
Les sous-programmes peuvent aussi renvoyer des rfrences. Cela peut sembler banal, mais vous tes parfois cens vous servir dun sous-programme pour renvoyer une rfrence, plutt que de crer la rfrence vous-mme. En particulier, des sous-programmes spciaux appels constructeurs crent et renvoient des rfrences sur des objets. Un objet est juste un type spcial de rfrence qui sait quelle classe il est associ ; les constructeurs savent crer ce genre dassociation. Ils les crent en prenant un rfrent ordinaire

2. Mais bien quil ny ait quun seul sous-programme anonyme, il peut y avoir plusieurs copies des variables lexicales utilises par le sous-programme, selon le moment o la rfrence a t gnre. Cela sera abord plus loin dans la section Fermetures.

customer_8566

Cration de rfrences

227

et en le transformant en objet grce loprateur bless (qui signifie bnir en anglais), cest pourquoi nous pouvons parler dobjets comme de rfrences consacres. Il ny a rien de religieux dans tout cela ; tant donn quune classe fonctionne comme un type dfini par lutilisateur, consacrer un rfrent en fait un type utilisateur en plus dun type prdfini. Les constructeurs sont souvent nomms new en particulier par les programmeurs C++ mais en Perl on peut les appeler comme on veut. Les constructeurs peuvent tre appels de nimporte laquelle de ces manires :
$refobj $refobj $refobj $refobj = = = = Chien::->new(Queue => courte, Oreilles => longues); #1 new Chien:: Queue => courte, Oreilles => longues; #2 Chien->new(Queue => courte, Oreilles => longues); #3 new Chien Queue => courte, Oreilles => longues; #4

La premire et la deuxime invocations sont identiques. Toutes deux appelent une fonction nomme new qui est fournie par le module Chien. Les troisime et quatrime invocations sont identiques aux deux premires mais sont lgrement plus ambigus : lanalyseur va se tromper si vous avez dfini votre propre fonction new et que vous navez fait ni de require, ni de use, sur le module Chien, chacun des deux ayant pour effet de dclarer le module. Dclarez toujours vos modules si vous voulez utiliser la mthode numro 4. (Et faites attention aux sous-programmes Chien errants.) Voir le chapitre 12, Objets, pour une discussion sur les objets Perl.

Rfrences de handles
Les rfrences un handle de fichier ou de rpertoire peuvent tre cres en prenant une rfrence un typeglob de mme nom :
bafouille(\*STDOUT); sub bafouille { my $fh = shift; print $fh "heu hum h bien a hmmm\n"; } $rec = get_rec(\*STDIN); sub get_rec { my $fh = shift; return scalar <$fh>; }

Si vous faites circuler des handles de fichier, vous pouvez aussi utiliser le typeglob seul pour le faire : dans lexemple ci-dessus, vous auriez pu utiliser *STDOUT ou *STDIN au lieu de \*STDOUT et \*STDIN. Bien que vous puissiez en gnral indiffrement utiliser les typeglobs et les rfrences de typeglob, il y a quelques cas o vous ne pouvez pas. Les typeglobs simples ne peuvent pas tre consacrs (avec bless) en objets et les rfrences de typeglobs ne peuvent tre passes en dehors de la porte dun typeglob localis. Pour gnrer de nouveaux handles de fichiers, du code ancien ferait plutt des choses comme ceci pour ouvrir une liste de fichiers :

customer_8566

228
for $fichier (@noms) { local *FH; open(*FH, $fichier) || next; $handle{$fichier} = *FH; }

Chapitre 8 Rfrences

a marche encore, mais de nos jours il est aussi facile de laisser une variable non dfinie sautovivifier en typeglob anonyme :
for $fichier (@names) { my $fh; open($fh, $fichier) || next; $handle{$fichier} = $fh; }

Avec les handles de fichiers indirects, que vous utilisiez des typeglobs, des rfrences de typeglob ou lun des objets dE/S plus exotiques na aucune importance. Vous utilisez simplement un scalaire qui dune manire ou dune autre sera interprt comme un handle de fichier. Dans la plupart des cas, vous pouvez utiliser un typeglob ou une rfrence un typeglob presque alatoirement. Comme nous lavons reconnu plus tt, ce qui se passe ici, cest la magie du drfrencement implicite.

Rfrences de table de symboles


Dans des circonstances inhabituelles, vous pourriez ne pas savoir de quel type de rfrence vous aurez besoin au moment o vous crivez votre programme. Une rfrence peut tre cre en utilisant une syntaxe spciale connue affectueusement sous le nom de syntaxe *foo{THING} (en anglais dans le texte). *toto{CHOSE} (en franais dans le texte) retourne une rfrence la case CHOSE de *toto, qui est lentre de la table de symbole contenant les valeurs de $toto, @toto, %toto et tous leurs amis.
$refscalaire $reftableau $refhash $refcode $refglob $refio = = = = = = *toto{SCALAR}; *ARGV{ARRAY}; *ENV{HASH}; *handler{CODE}; *toto{GLOB}; *STDIN{IO}; # # # # # # Mme chose Mme chose Mme chose Mme chose Mme chose Euh... que que que que que \$toto \@ARGV \%ENV \&handler \*toto

Les noms parlent deux-mmes, sauf dans le cas de *STDIN{IO}. Il contient lobjet interne IO::Handle que le typeglob contient, cest--dire la partie du typeglob qui intresse vritablement les diffrentes fonctions dentre/sortie. Pour assurer la compatibilit avec les anciennes versions de Perl, *toto{FILEHANDLE} est un synonyme de la notation *toto{IO} la mode. En thorie, vous pouvez utiliser un *HANDLE{IO} partout o vous auriez utilis un *HANDLE ou un \*HANDLE, comme par exemple pour passer des handles des fonctions ou pour en retourner, ou pour les stocker dans des structures plus grandes. (En pratique il reste encore quelques obstacles aplanir.) Leur avantage est quils accdent uniquement au vritable objet dE/S qui vous intresse et pas tout le typeglob, donc vous ne courez pas le risque de dfaire plus de choses que vous ne voulez par une affectation de typeglob (mais si vous voulez assigner une variable scalaire au lieu dun typeglob, cela ne posera pas de problme). Un des inconvnients est quil nest pas possible den autovivi-

customer_8566

Utilisation des rfrences en dur


fier lheure actuelle.3
bafouille(*STDOUT); bafouille(*STDOUT{IO}); sub bafouille { my $fh = shift; print $fh "heu hum h bien a hmmm\n"; }

229

Les deux invocations de bafouille() affichent heu hum h bien a hmmm . *toto{CHOSE} renvoie undef si cette CHOSE en particulier na pas encore t vue par le compilateur, sauf si CHOSE vaut SCALAR. Il se trouve que *toto{SCALAR} renvoie une rfrence un scalaire anonyme mme si $toto na pas encore t vu. (Perl ajoute toujours le scalaire au typeglob pour optimiser un bout de code ailleurs. Mais ne supposez pas que cela restera ainsi dans les prochaines versions.)

Cration implicite de rfrences


Une dernire mthode de cration de rfrences nen est pas vraiment une. Les rfrences dun certain type se mettent simplement exister quand vous les drfrencez dans un contexte de lvalue qui suppose quelle existent. Cela est extrmement utile, et cest aussi Ce Quoi On sAttend. Ce sujet est trait plus loin dans ce chapitre, quand nous verrons comment drfrencer toutes les rfrences que nous avons cres jusquici.

Utilisation des rfrences en dur


Tout comme il existe de nombreuses manires de crer des rfrences, il existe galement plusieurs manires dutiliser, ou de drfrencer une rfrence. Il existe un seul principe suprieur : Perl ne fait pas de rfrencement ou de drfrencement implicite.4 Quand un scalaire contient une rfrence, il se comporte comme un simple scalaire. Il ne devient pas magiquement un tableau ou un hachage ou un sous-programme ; vous devez lui signifier explicitement de le faire, en le drfrenant.

Emploi dune variable comme nom de variable


Quand vous rencontrez un scalaire comme $toto, vous devriez penser la valeur scalaire associe toto . Cest--dire quil y a une entre toto dans la table des symboles et que le drle de caractre $ est une manire de regarder quelle valeur scalaire se trouve lintrieur. Si ce qui se trouve lintrieur est une rfrence, vous pouvez regarder lintrieur de cette rfrence (drfrencer $toto en le faisant prcder dun autre drle de caractre. Ou en le regardant du point de vue oppos, vous pouvez remplacer le toto littral dans $toto par une variable scalaire qui pointe sur le vritable rfrent. Cela est
3. Aujourdhui, open my $fh autovivifie un typeglob au lieu dun objet IO::Handle ; mais un des ces jours nous corrigerons cela, aussi ne devriez vous pas vous fier au fait quopen autovivifie actuellement un typeglob. 4. Nous avons dj reconnu que ctait un petit mensonge. Nous nallons pas recommencer.

customer_8566

230

Chapitre 8 Rfrences

vrai pour tout type de variable, donc non seulement $$toto est la valeur scalaire de ce quoi $toto se rfre, mais @$titi est la valeur tableau de ce quoi $titi se rfre, %$tutu est la valeur hachage de ce quoi $tutu se rfre, et ainsi de suite. Le rsultat est que vous pouvez rajouter un drle de caractre devant nimporte quelle valeur scalaire pour la drfrencer :
$toto $refscalaire = "trois bosses"; = \$toto; # # $type_chameau = $$refscalaire; # # $refscalaire est maintenant une rfrence $toto $type_chameau vaut maintenant "trois bosses"

Voici dautres drfrences :


$titi = $$refscalaire; push(@$reftableau, $fichier); $$reftableau[0] = "Janvier";

# # @$reftableau[4..6] = qw/Mai Juin Juillet/; # #

Affecte le premier lment de @$reftableau Affecte plusieurs lments de @$reftableau

%$refhash = (CLE => "TROUSSEAU", OISEAU => "SIFFLER");

# Initialise tout # le hash $$refhash{CLE} = "VALEUR"; # Change un couple cl/valeur @$refhash{"CLE1","CLE2"} = ("VAL1","VAL2"); # Ajoute deux nouveaux couples &$refcode(1,2,3); print $refhandle "sortie\n";

Cette forme de drfrencement ne peut utiliser quune variable simple (sans indice). Cest--dire que le drfrencement se produit avant (ou lie plus fort que) toute recherche dans un tableau ou un hachage. Utilisons des accolades pour clarifier notre pense : une expression comme $$reftableau[0] est quivalente ${$reftableau}[0] et signifie le premier lment du tableau rfrenc par $reftableau. Ce nest pas du tout la mme chose que ${$reftableau[0]} qui drfrence le premier lment du tableau nomm @reftableau (et qui nexiste probablement pas). De mme, $$refhash{CLE} est quivalent ${$refhash}{CLE} et na rien voir avec ${$refhash{CLE}} qui drfrencerait une entre du hachage nomm %refhash (qui nexiste probalement pas). Vous serez malheureux tant que vous naurez pas compris cela. Vous pouvez raliser plusieurs niveaux de rfrencement et de drfrencement en concatnant les drles de caractres de faon approprie. Ce qui suit affiche salut :
$refrefref = \\\"salut"; print $$$$refrefref;

Vous pouvez voir les dollars comme oprant de droite gauche. Mais le dbut de la chane doit toujours tre un simple scalaire sans indice. Il existe cependant une technique qui met un peu plus de fantaisie, que nous avons dj subrepticement utilise un peu plus tt, et que nous allons expliquer dans la section suivante.

customer_8566

Utilisation des rfrences en dur

231

Emploi dun BLOC comme nom de variable


Non seulement vous pouvez drfrencer un simple nom de variable, mais vous pouvez aussi drfrencer le contenu dun BLOC. Partout o vous mettriez un identificateur comme partie dune variable ou dun nom de sous-programme, vous pouvez remplacer lidentificateur par un BLOC qui renvoie une rfrence du bon type. En dautres termes, tous les exemple prcdents peuvent tre clarifis comme suit :
$titi = ${$refscalaire}; push(@{$reftableau}, $fichier); ${$reftableau}[0] = "Janvier"; @{$reftableau}[4..6] = qw/Mai Juin Juillet/; ${$refhash}{"CLE"} = "VALEUR"; @{$refhash}{"CLE1","CLE2"} = ("VAL1","VAL2"); &{$refcode}(1,2,3);

sans oublier :
$refrefref = \\\"salut"; print ${${${$refrefref}}};

Nous sommes daccord quil est idiot de mettre des accolades dans des cas aussi simples, mais le BLOC peut contenir nimporte quelle expression. En particulier, il peut contenir une expression avec des indices. Dans lexemple suivant, on suppose que $dispatch{$index}} contient une rfrence un sous-programme (parfois appel coderef ). Lexemple appelle le sous-programme avec trois arguments.
&{ $dispatch{$index} }(1, 2, 3);

Ici le BLOC est indispensable. Sans le couple daccolades extrieures, Perl aurait trait $dispatch comme le coderef la place de $dispatch{$index}.

Emploi de loprateur flche


Dans le cas de hachages, de tableaux ou de sous-programmes, une troisime mthode de drfrencement implique lutilisation de loprateur infixe ->. Cette forme de sucre syntaxique facilite laccs un lment individuel dun tableau ou dun hachage, ainsi que lappel indirect un sous-programme. Le type de drfrencement est dtermin par loprande de droite, cest--dire par ce qui suit directement la f lche. Si ce qui suit la f lche est un crochet ou une accolade, loprande de gauche est trait respectivement comme une rfrence un tableau ou un hachage, index par lexpression droite. Si ce qui suit est une parenthse ouvrante, loprande de gauche est trait comme un sous-programme appeler avec les paramtres fournis entre les parenthses droite. Chacun des trios qui suivent sont quivalents et correspondent aux trois notations que nous avons prsentes. (Nous avons rajout des espaces pour que les lments qui se correspondent soient aligns.)
$ $reftableau [2] = "Dorian"; ${ $reftableau }[2] = "Dorian"; $reftableau->[2] = "Dorian"; #1 #2 #3

customer_8566

232
$ $refhash {TON} = "Fa#majeur"; ${ $refhash }{TON} = "Fa#majeur"; $refhash->{TON} = "Fa#majeur"; & $refcode (Presto => 192); &{ $refcode }(Presto => 192); $refcode->(Presto => 192); #1 #2 #3 #1 #2 #3

Chapitre 8 Rfrences

Vous pouvez voir que le premier drle de caractre manque dans la troisime notation de chaque srie. Le drle de caractre est devin par Perl, ce qui fait que cette notation ne peut servir pour drfrencer des tableaux ou des hachages entiers, ni mme des tranches de ceux-ci. Cependant, tant que vous vous en tenez des valeurs scalaires, vous pouvez utiliser nimporte quelle expression gauche de ->, y compris un autre drfrencement, car plusieurs oprateurs f lches sassocient de gauche droite :
print $tableau[3]->{"Anglais"}->[0];

Vous pouvez dduire de cette expression que le quatrime lment de @tableau est suppos tre une rfrence un hachage, et que la valeur associe lentre Anglais de ce hachage est suppose tre une rfrence un tableau. Remarquez que $tableau[3] et $tableau->[3] ne sont pas les mmes. Le premier donne le quatrime lment de @tableau, tandis que le second donne le quatrime lment du tableau (peut-tre anonyme) dont la rfrence se trouve dans $tableau. Supposez maintenant que $tableau[3] soit indfini. Linstruction suivante est toujours lgale :
$tableau[3]->{"Anglais"}->[0] = "January";

Cest lun des cas que nous avons mentionn prcdemment o les rfrences se mettent exister (ou sont autovivifies ) quand on les utilise comme des lvalues (cest--dire quand une valeur leur est affecte). Si $tableau[3] tait indfini, il est automatiquement dfini comme une rfrence un hachage afin que nous puissions affecter une valeur $tableau[3]->{"Anglais"} lintrieur. Une fois que cest fait, $tableau[3]>{"Anglais"} est automatiquement dfini comme une rfrence un tableau, afin que nous puissions affecter une valeur au premier lment de ce tableau. Remarquez que les rvalues (les valeurs droite dune affectation) sont lgrement diffrentes : print $tableau[3]->{"Anglais"}->[0] ne cre que $tableau[3] et $tableau[3]->{"Anglais"}, et pas $tableau[3]->{"Anglais"}->[0], puisque le dernier lment nest pas une lvalue. (Le fait que cela dfinisse les deux premiers dans un contexte de rvalue devrait tre considr comme une bogue. Nous corrigerons peut-tre cela un jour.) La f lche est optionnelle entre les indices dlimits par des accolades ou des crochets, et entre une accolade ou un crochet fermant et une parenthse destine un appel de fonction indirect. Vous pouvez donc rduire le code prcdent :
$dispatch{$index}(1, 2, 3); $tableau[3]{"Anglais"}[0] = "January";

Dans le cas des tableaux ordinaires, cela vous permet davoir des tableaux multidimensionnels exactement comme ceux de C :
$reponse[$x][$y][$z] += 42;

Bon daccord, pas exactement comme ceux de C. Dabord C ne sait pas comment faire grossir ses tableaux la demande, comme Perl. Ensuite certaines constructions similai-

customer_8566

Utilisation des rfrences en dur

233

res dans les deux langages sont analyses diffremment. En Perl, les deux instructions suivantes font la mme chose :
$refliste->[2][2] = "coucou"; $$refliste[2][2] = "coucou"; # Assez clair # Prte confusion

La seconde instruction peut choquer le programmeur C, qui est habitu utiliser *a[i] pour signifier ce qui est point par le ie lment de a . Mais en Perl, les cinq caractres ($ @ * % &) lient plus troitement que les accolades ou les crochets.5 Cest donc $$refliste et non $refliste[2] qui est pris comme rfrence un tableau. Si vous voulez le comportement de C, soit vous devez crire ${$refliste[2]} pour forcer lvaluation de $refliste[2] avant le premier $drfrenceur, ou bien utiliser la notation -> :
$refliste[2]->[$salutation] = "coucou";

Emploi des mthodes dobjets


Si une rfrence se trouve tre une rfrence un objet, alors la classe qui dfinit cet objet fournit probablement des mthodes pour accder ce quil contient, et vous devriez gnralement vous en tenir ces mthodes si vous ne faites quutiliser la classe (par opposition ceux qui limplmentent). En dautres termes, soyez correct et ne traitez pas un objet comme une simple rfrence, bien que Perl vous laisse faire si vous le devez vraiment. Perl nimpose pas lencapsulation. Nous ne sommes pas des dictateurs. Mais nous esprons cependant un peu de civilit de votre part. En retour de cette civilit, vous gagnez un complte orthogonalit entre les objets et les structures de donnes. Toute structure de donnes peut se comporter comme un objet, si vous le voulez. Et ne pas le faire, si vous ne voulez pas.

Pseudo-hachages
Un pseudo-hachage est une rfrence un tableau dont le premier lment est une rfrence un hachage. Vous pouvez traiter le pseudo-hachage soit comme une rfrence de tableau (comme vous pouviez vous y attendre) ou comme une rfrence de hachage (ce quoi vous ne vous attendiez peut-tre pas). Voici un exemple de pseudo-hachage :
$john = [ {age => 1, yeux => 2, poids => 3}, 47, "marron", 84 ];

Le hachage sous-jacent dans $john->[0] dfinit les noms "age", "yeux" et "poids" des lments de tableau qui suivent (47, "marron" et 84). Maintenant vous pouvez accder un lment la fois par la notation de hachage et par celle de tableau :
$john->{poids} $john->[3] # Traite $john comme une rfrence de hachage # Traite $john comme une rfrence de tableau

La magie des pseudo-hachages nest pas trs puissante ; ils ne connaissent quun seul tour : comment transformer un drfrencement de hachage en drfrencement de tableau. Quand vous ajoutez un nouvel lment au pseudo-hachage, vous devez ex5. Mais pas cause de la prcdence des oprateurs. Les drles de caractres de Perl ne sont pas des oprateurs dans ce sens-l. La grammaire de Perl interdit simplement tout ce qui est plus compliqu quune simple variable ou un bloc de suivre le drle de caractre initial, pour plein de drles de raisons.

customer_8566

234

Chapitre 8 Rfrences

plicitement prciser au hachage de correspondance sous-jacent o llment va rsider avant dutiliser la notation de hachage :
$john->[0]{hauteur} = 4; $john->{hauteur} = "grand"; # hauteur sera llment 4 # Ou $john->[4] = "grand"

Perl lve une exception si vous essayez deffacer une cl de pseudo-hachage, bien que vous puissiez toujours effacer une cl du hachage de correspondance. Perl lve galement une exception si vous essayez daccder une cl qui nexiste pas ( existence signifiant ici prsence dans le hachage de correspondance ).
delete $john->[0]{hauteur}; $john->{hauteur}; $john->[4]; # # # # Supprime seulement dans le hachage sous-jacent Ceci lve dsormais une exception Affiche toujours "grand"

Ne tentez pas de splice du tableau sans savoir ce que vous faites. Si les lments du tableau se dplacent, les valeurs de correspondance du hachage feront toujours rfrence aux anciennes positions des lments, moins que vous ne les changiez elles aussi explicitement. La magie des pseudo-hachages nest pas trs puissante. Pour viter les incohrences, vous pouvez utiliser la fonction fields::phash fournie par le pragma use fields pour crer un pseudo-hachage :
use fields; $ph = fields::phash(age => 47, yeux => "marron", poids => 84); print $ph->{age};

Il existe deux manires de vrifier lexistence dune cl dans un pseudo-hachage. La premire est dutiliser exists, qui vrifie si le champ fourni a jamais t affect. Il fonctionne de cette faon pour reproduire le comportement dun vritable hachage. Par exemple :
use fields; $ph= fields::phash([qw(age yeux poids)], [47]); $ph->{yeux} = undef; print exists $ph->{age}; # Vrai, age a t modifi dans la dclaration. print exists $ph->{poids}; # Faux, poids na pas t utilis. print exists $ph->{yeux}; # Vrai, les yeux ont t modifis.

La seconde manire est dutiliser exists sur le hachage de correspondance install dans le premier lment. Ceci vrifie que la cl donne est un champ valide pour ce pseudohachage :
print exists $ph->[0]{age}; # Vrai, age est un champ valide print exists $ph->[0]{nom}; # Faux, nom ne peut pas tre utilis

Contrairement ce qui se produit pour un vritable hachage, appeler delete sur un lment de pseudo-hachage nefface que la valeur dans le tableau, et pas la cl dans le hachage de correspondance. Pour effacer la cl, vous devrez leffacer explicitement du hachage de correspondance. Une fois que cela est fait, vous ne pouvez plus utiliser ce nom de cl comme indice du pseudo-hachage :
print delete $ph->{age}; print exists $ph->{age}; # Dtruit $ph->[1], 47 et le renvoie # Maintenant cest faux.

customer_8566

Utilisation des rfrences en dur


print exists $ph->[0]{age}; # Vrai, age est encore utilisable print delete $ph->[0]{age}; # Maintenant age nexiste plus print $ph->{age}; # Exception lexcution

235

Vous commencez srement vous demander ce qui a pu motiver ce carnaval de tableaux se promenant dans un habit de hachage. Les tableaux fournissent un accs plus rapide et un stockage plus efficace, tandis que les hachages offrent la possibilit de nommer (au lieu de numroter) vos donnes ; les pseudo-hachages offrent le meilleur des deux mondes. Mais cest en considrant la phase de compilation de Perl que vous verrez apparatre le meilleur bnfice de lopration. Avec laide dun pragma ou deux, le compilateur peut vrifier laccs correct aux champs valides, aussi pouvez-vous vrifier linexistence dun champ (ou les fautes dorthographe) avant le dbut de votre programme. Les proprits de vitesse, defficacit, de vrification daccs la compilation (vous pouvez mme le voir comme de la validation de type) sont particulirement pratiques pour crer des modules de classes robustes et efficaces. Voir la discussion du pragma use fields au chapitre 12 et au chapitre 31, Modules de pragmas. Les pseudo-hachages sont une fonctionnalit nouvelle et relativement exprimentale ; en tant que telle, limplmentation en interne est susceptible de changer lavenir. Afin de vous protger de tels changements, utilisez toujours linterface documente du module fields, en utilisant ses fonctions phash et new.

Dautres tours avec les rfrences en dur


Comme mentionn prcdemment, loprateur antislash est en gnral utilis sur un seul rfrent pour gnrer une rfrence unique, mais ce nest pas obligatoire. Quand il est utilis sur une liste de rfrents, il produit une liste de rfrences correspondantes. La seconde ligne de lexemple suivant produit exactement le mme resultat que la premire, car lantislash est automatiquement distribu sur toute la liste.
@listeref = (\$s, \@a, \%h, \&f); @listeref = \($s, @a %h, &f); # Liste de quatre rfrences # Mme chose

Si une expression entre parenthses contient exactement un tableau ou un hachage, toutes ses valeurs sont interpoles et des rfrences sont renvoyes pour chacune :
@listeref = \(@x); @listeref = map { \$_ } @x; @listeref = \(@x, (@y)); @listeref = (\@x, map { \$_ } @y); # Interpole le tableau puis prend # les rfrences # Mme chose # Seuls les aggrgats simples sont # interpols # Mme chose

Cela se produit galement quand il y a des parenthses lintrieur :

Si vous essayez cela avec un hachage, le rsultat contiendra des rfrences aux valeurs (comme vous vous y attendez), mais aussi des rfrences des copies des cls (comme vous en vous y attendez peut-tre pas). Comme les tranches de tableaux et de hachages sont seulement des listes, vous pouvez antislasher des tranches de lun ou lautre type pour obtenir une liste de rfrences. Chacune des trois listes suivantes fait exactement la mme chose :

customer_8566

236

Chapitre 8 Rfrences

@envrefs = \@ENV{HOME, TERM}; # Antislashe une tranche @envrefs = \( $ENV{HOME}, $ENV{TERM} ); # Antislashe une liste @envrefs = ( \$ENV{HOME}, \$ENV{TERM} ); # Une liste de deux rfrences

Comme les fonctions peuvent retourner des listes, vous pouvez leur appliquer loprateur antislash. Si vous avez plusieurs appels de fonction, interpolez dabord la valeur de retour de chaque fonction dans une liste plus grande avant dantislasher lensemble :
@listeref = \fx(); @listeref = map { \$_ } fx(); @listeref = \( fx(), fy(), fz() ); @listeref = ( \fx(), \fy(), \fz() ); @listeref = map { \$_ } fx(), fy(), fz(); # Mme chose

# Mme chose # Mme chose

Comme loprateur antislash fourni un contexte de liste ses oprandes, ces fonctions sont toutes appeles en contexte de liste. Si lantislash est lui-mme en contexte scalaire, vous finirez avec une rfrence la dernire valeur de la liste renvoye par la fonction :
@listeref = \localtime(); $reffinale = \localtime(); # Ref chacun des neuf lments de la date # Ref lindicateur de lheure dt

cet gard, loprateur antislash se comporte comme les oprateurs de liste nomms, comme print, reverse et sort, qui fournissent toujours un contexte de liste leur droite, quoiquil se passe leur gauche. Comme avec les oprateurs de liste nomms, utilisez un scalar explicite pour forcer ce qui suit tre en contexte de liste :
$refdate = \scalar localtime(); # \"Thu Jul 26 11:37:38 2001"

Vous pouvez vous servir de loprateur ref pour dterminer vers quoi une rfrence pointe. Vous pouvez voir loprateur ref comme un oprateur typeof qui renvoie vrai si son argument est une rfrence et faux dans le cas contraire. La valeur renvoye dpend du type de chose rfrence. Les types prdfinis comprennent SCALAR, ARRAY, HASH, CODE, GLOB, REF, LVALUE, IO, IO::Handle et Regexp. Ici, nous nous en servons pour valider les arguments dun sous-programme :
sub somme { my $reftableau = shift; warn "Ce nest pas une rfrence de tableau" if ref($reftableau) ne "ARRAY"; return eval join("+", @$reftableau); }

Si vous utilisez une rfrence en dur dans un contexte de chane, elle sera convertie en une chane contenant le type et ladresse : SCALAR(0x1fc0e). (La conversion inverse ne peut pas tre faite, puisque linformation de dcompte de rfrences est perdue pendant lopration de conversion en chane et aussi car il serait dangereux de laisser des programmes accder une adresse mmoire donne par une chane arbitraire.) Vous pouvez utiliser loprateur bless pour associer un rfrent un paquetage fonctionnant comme une classe dobjet. Quand vous faites cela, ref renvoie le nom de la classe au lieu du type interne. Une rfrence dobjet utilise en contexte de chane renvoie une chane avec les types interne et externe, ainsi que ladresse en mmoire : MonType=HASH(0x20d10) ou IO::Handle=IO(0x186904). Pour plus de dtails sur les objets, voir le chapitre 12.

customer_8566

Utilisation des rfrences en dur

237

Puisque le type de rfrent que vous dsirez est indiqu par la faon dont vous le drfrencez, un typeglob peut tre utilis de la mme faon quune rfrence, malgr le fait quun rfrent contienne plusieurs rfrents de types divers. ${*main::toto} et ${\$main::toto} accdent donc tous deux la mme variable scalaire, mme si le second est plus efficace. Voici une astuce pour interpoler la valeur de retour dun appel de fonction dans une chane :
print "Ma fonction a renvoy @{[ mafonction(1,2,3) ]} cette fois.\n";

Voici comment cela fonctionne. la compilation, quand le @{...} est vu lintrieur de la chane entre guillemets doubles, il est analys comme un bloc qui renvoie une rfrence. lintrieur du bloc, les crochets crent une rfrence un tableau anonyme partir de ce qui se trouve entre eux. lexcution, mafonction(1,2,3) est donc appele en contexte de liste, et les rsultats sont chargs dans un tableau anonyme dont une rfrence est renvoye lintrieur du bloc. Cette rfrence de tableau est immdiatement drfrence par le @{...} qui lentoure, et la valeur de tableau est interpole dans la chane doubles guillemets tout comme un tableau ordinaire le serait. Ce stratagme savre galement utile pour des expressions quelconques, comme :
print "Il nous faut @{ [$n + 5] } machins !\n";

Cependant faites attention : les crochets fournissent un contexte de liste leur expression. Dans ce cas, cela na aucune importance, mais lappel prcdent mafonction aurait pu y tre sensible. Quand il le faut, utilisez un scalar explicite pour forcer le contexte :
print "mafonction renvoie @{ [scalar mafonction(1,2,3)] } maintenant.\n";

Fermetures
Nous avons parl plus haut de la cration de sous-programmes anonymes avec un sub {} sans nom. Vous pouvez voir ces sous-programmes comme sils taient dfinis lexcution, ce qui signifie quils ont un instant de gnration en plus dune position de dfinition. Certaines variables pourraient tre porte quand le sous-programme est cr, et dautres variables pourraient tre porte quand le sous-programme est appel. Oubliez les sous-programmes pour le moment et considrez une rfrence qui se rfre une variable lexicale :
{ my $bestiau = "chameau"; $refbestiau = \$creature; }

La valeur de $$refbestiau restera chameau bien que $bestiau disparaisse aprs laccolade fermante. Mais $refbestiau aurait trs bien pu faire rfrence un sous-programme qui se rfre $bestiau :
{ my $bestiau = "chameau"; $refbestiau = sub { return $bestiau }; }

customer_8566

238

Chapitre 8 Rfrences

Cest une fermeture, qui est une notion sortie du monde de la programmation fonctionnelle de LISP et Scheme.6 Cela signifie que quand vous dfinissez un sous-programme anonyme dans une porte lexicale particulire un moment donn, il prtend continuer fonctionner dans cette porte particulire, mme si vous lappelez plus tard depuis lextrieur de cette porte. (Un puriste dirait quil na pas besoin de prtendre il fonctionne rellement dans cette porte.) En dautres termes, vous tes assur de garder la mme copie dune variable lexicale chaque fois, mme si dautres instances de cette variable lexicale ont t cres avant ou aprs pour dautres instances de cette fermeture. Cela vous permet de dajuster les valeurs utilises par un sous-programme quand vous le dfinissez, et pas seulement quand vous lappelez. Vous pouvez aussi voir les fermetures comme une manire dcrire un patron de sousprogramme sans utiliser eval. Les variables lexicales servent de paramtres pour remplir le modle, ce qui est utile pour configurer des petits bouts de code excuter plus tard. On les appelle communment des fonctions de rappel en programmation vnementielle, quand vous associez un bout de code la pression dune touche, un clic de souris, lexposition dune fentre et ainsi de suite. Quand on les utilise comme des fonctions de rappel, les fermetures font exactement ce quoi vous vous attendez, mme si vous ne connaissez rien la programmation fonctionnelle. (Remarquez que cette histoire de fermeture ne sapplique quaux variables my. Les variables globales fonctionnent comme elles ont toujours fonctionn, tant cres et dtruites de faon compltement diffrente des variables lexicales. Une autre utilisation des fermetures se fait lintrieur de gnrateurs de fonctions ; cest-dire de fonctions qui crent et retournent de nouvelles fonctions. Voici un exemple de gnrateur de fonction implment avec des fermetures :
sub faitbonjour { my $salut = shift; my $newfunc = sub { my $cible = shift; print "$salut, $cible !\n"; }; return $newfunc; # Renvoie une fermeture } $f = faitbonjour("Bonjour"); # Cre une fermeture $g = faitbonjour("Salutations"); # Cre une autre fermeture # Le temps passe... $f->("monde"); $g->("Terriens");

Cela affiche :
Bonjour, monde ! Salutations, Terriens !
6. Dans ce contexte, fonctionnel ne doit pas tre interprt comme le contraire de dysfonctionnel .

customer_8566

Utilisation des rfrences en dur

239

Remarquez en particulier comme $salut continue de faire rfrence la valeur effectivement passe faitbonjour, malgr le fait que le my $salut soit hors de porte quand le sous-programme anonyme tourne. Cest tout lintrt des fermetures. Comme $f et $g contiennent des rfrences des fonctions qui, quand on les appelle, ont toujours besoin daccder des versions distinctes de $salut, ces versions restent automatiquement dans les environs. Si maintenant vous effacez $f, sa version de $salut disparaitra automatiquement. (Perl nettoie quand vous avez le dos tourn.) Perl ne fournit pas de rfrences aux mthodes dobjets (dcrites au chapitre 12) mais vous pouvez obtenir un effet similaire en utilisant une fermeture. Supposons que vous voulez une rfrence, pas seulement la fonction que la mthode reprsente, mais aussi une rfrence qui, quand vous linvoquez, appelle cette mthode sur un objet particulier. Vous pouvez commodment vous souvenir la fois de lobjet et de la mthode en en faisant des variables lexicales lies une fermeture :
sub get_ref_methode { my ($self, $nommethode) = @_; my $refmeth = sub { # le @_ ci-dessous est diffrent de celui au-dessus ! return $self->$nommethode(@_); }; return $refmeth; } my $toutou = new Chien:: Nom => "Lucky", Pattes => 3, Queue => "coupe"; our $remueur = get_ref_methode($toutou, remuer); $remueur->("queue"); # Appelle $dog->remuer(queue).

Vous pouvez donc demander Lucky de remuer ce qui lui reste de queue mme quand la variable lexicale $toutou est hors de porte et que Lucky nest plus visible. La variable globale $remueur peut toujours lui faire remuer la queue, o quil se trouve.

Fermetures comme modles de fonctions


Utiliser une fermeture comme modle de fonctions vous permet de gnrer plusieurs fonctions qui agissent de faon similaire. Supposons que vous voulez une suite de fonctions qui gnrent des changements de fonte HTML pour diverses couleurs :
print "Soyez ", rouge("prudent"), "avec cette ", vert("lumire"), " !!!";

Les fonctions rouge et vert seraient trs similaires. Nous aimerions bien nommer nos fonctions, mais les fermetures nont pas de nom puisquil sagit juste de routines qui sy croient. Pour contourner cela, nous allons utiliser une jolie astuce pour nommer nos sous-programmes anonymes. Vous pouvez lier une rfrence de code un nom existant en laffectant au typeglob du nom de la fonction que vous voulez. (Voir la section Tables de symboles au chapitre 10, Paquetages). Dans ce cas, nous allons la lier deux noms diffrents, lun en majuscules et lautres en minuscules :
@couleurs = qw(red blue green yellow orange purple violet);

customer_8566

240

Chapitre 8 Rfrences

for my $nom (@couleurs) { no strict refs; # Autorise les rfrences symboliques *$nom = *{uc $nom} = sub { "<FONT COLOR=$nom>;@_</FONT>" }; }

Vous pouvez maintenant appeler les fonctions nommes red, RED, blue, BLUE et ainsi de suite, et la fermeture approprie sera invoque. Cette technique rduit la dure de compilation et conserve la mmoire ; elle est aussi moins susceptible derreur, puisque la vrification de syntaxe se fait la compilation. Il est impratif que les variables dans le sous-programme anonyme soient lexicales afin de crer une fermeture. Cest la raison du my dans lexemple ci-dessus. Voici lun des rares cas o donner un prototype une fermeture sert quelque chose. Si vous aviez voulu imposer un contexte scalaire aux arguments de ces fonctions (ce nest probablement pas une bonne ide pour cet exemple), vous auriez plutt crit ceci :
*$nom = sub ($) { "<FONT COLOR=$nom>$_[0]</FONT>" };

Cest presque suffisant. Cependant comme la vrification de prototypes se produit la compilation, laffectation lexcution se produit trop tard pour servir quelque chose. Vous pouvez corriger cela en mettant toute la boucle daffectations dans un bloc BEGIN qui la forcera se produire la compilation. (Plus probalement, vous la mettriez dans un module sur lequel vous ferez un use la compilation.) Les prototypes seront alors visibles pour le reste de la compilation.

Sous-programmes embots
Si vous avez lhabitude (prise dans dautres langages de programmation) dutiliser des procdures embotes dans dautres procdures, chacune avec ses propres variables prives, il va vous falloir travailler un peu en Perl. Les sous-programmes nomms ne sembotent pas bien, alors que les sous-programmes anonymes le peuvent.7 De toute faon, nous pouvons muler des sous-programmes embots porte lexicale laide de fermetures. En voici un exemple :
sub exterieur { my $x = $_[0] + 35; local *interieur = sub { return $x * 19 }; return $x + interieur(); }

Maintenant interieur ne peut tre appel que depuis exterieur cause de laffectation temporaire de la fermeture. Mais quand il lest, il a accs normalement la variable lexicale $x depuis la porte de exterieur. Ceci a lintressant effet de crer une fonction locale une autre, ce qui est quelque chose qui nest normalement pas support en Perl. Comme local est porte dynamique, et parce que les noms de fonctions sont globaux leur paquetage, toute autre fonction qui serait appele par exterieur pourrait aussi appeler la version temporaire
7. Pour tre plus prcis, les sous-programmes ayant un nom global ne sembotent pas. Malheureusement cest le seul type de dclaration de sous-programmes nomms que nous ayons. Nous navons pas encore implment les sous-programmes nomms porte lexicale (connus sous le nom de my sub), mais quand nous le ferons, ils semboteront correctement.

customer_8566

Rfrences symboliques

241

dinterieur. Pour empcher cela, il vous faudra un niveau supplmentaire dindirection :


sub exterieur { my $x = $_[0] + 35; my $interieur = sub { return $x * 19 }; return $x + $interieur->(); }

Rfrences symboliques
Que se passe-t-il si vous essayez de drfrencer une valeur qui nest pas une rfrence en dur ? La valeur est alors traite comme une rfrence symbolique. Cest--dire que la rfrence est interprte comme une chane reprsentant le nom dune variable globale. Voici comment cela fonctionne :
$nom = "bam"; $$nom = 1; $nom->[0] = 4; $nom->{X} = "Y"; @$nom = (); keys %$nom; &$nom; # # # # # # Dfinit $bam Dfinit le premier lment de @bam Dfinit llment X de %bam Y Vide @bam Renvoie les cls de %bam Appelle &bam

Cest trs puissant et lgrement dangereux, en ce quil est possible de vouloir (avec la plus grande sincrit) utiliser une rfrence en dur, mais daccidentellement utiliser une rfrence symbolique la place. Pour vous protger contre cela, vous pouvez crire :
use strict refs;

et seules les rfrences en dur seront autorises dans le reste du bloc englobant. Un bloc intrieur peut suspendre cette restriction par :
no strict refs;

Il est aussi important de comprendre la diffrence entre les deux lignes de code suivantes :
${identificateur}; # Comme $identificateur. ${"identificateur"}; # $identificateur aussi, mais une rfrence symbolique.

Parce que la seconde forme est entre guillemets, elle est traite comme une rfrence symbolique, et gnrera une erreur avec use strict refs. Mme si use strict refs nest pas activ, elle peut seulement faire rfrence une variable de paquetage. Mais la premire forme est identique la forme sans accolades, et fera mme rfrence une variable porte lexicale sil y en a de dclare. Lexemple suivant le montre (et la section suivante en parle). Seules les variables de paquetage sont accessibles par des rfrences symboliques, car les rfrences symboliques passent toujours par la table de symboles du paquetage. Comme les variables lexicales ne se trouvent pas la table de symboles, elles sont invisibles pour ce mcanisme. Par exemple :
our $valeur = "globale";

customer_8566

242
{ my $valeur = "prive"; print " lintrieur, my est ${valeur}, "; print "mais our est ${valeur}.\n";

Chapitre 8 Rfrences

} print " lextrieur, ${valeur} est de nouveau ${valeur}.\n";

ce qui affiche :
lintrieur, my est prive, mais our est globale. lextrieur, globale est de nouveau globale.

Accolades, crochets et guillemets


Dans la section prcdente nous avons vu que ${identificateur} nest pas trait comme une rfrence symbolique. Vous vous demandez srement comment cela peut interagir avec les mots rservs. La rponse est que cela ninteragit pas. Bien que push soit un mot rserv, ces deux instructions affichent pop par dessus :
$push = "pop par "; print "${push}dessus";

La raison en est quhistoriquement, cette utilisation des accolades est celle des shells Unix pour isoler un nom de variable du texte alphanumrique qui le suit, et qui aurait sinon t interprt comme faisant partie du nom. Cest la faon dont beaucoup de gens sattendent voir fonctionner linterpolation, aussi lavons nous fait fonctionner de la mme faon en Perl. Mais en Perl cette notion stend plus loin, et sapplique galement aux accolades utilises pour gnrer les rfrences, quelles soient ou non entre guillemets. Cela signifie que :
print ${push} . dessus;

ou mme (puisque les blancs ne changent rien) :


print ${ push } . dessus;

affichent tous deux pop par dessus , mme si les accolades sont en dehors des guillemets doubles. La mme rgle sapplique tout identificateur utilis pour indexer un hachage. Ainsi, au lieu dcrire :
$hash{ "aaa" }{ "bbb" }{ "ccc" }

vous pouvez simplement crire :


$hash{ aaa }{ bbb }{ ccc }

ou :
$hash{aaa}{bbb}{ccc}

sans vous soucier de savoir si les indices sont des mots rservs. Donc ceci :
$hash{ shift }

est interprt comme $hash{"shift"}. Vous pouvez forcer linterprtation comme un mot rserv en ajoutant quelque chose qui le diffrencie dun identificateur :
$hash{ shift() } $hash{ +shift } $hash{ shift @_ }

customer_8566

Accolades, crochets et guillemets

243

Les rfrences ne fonctionnent pas comme cls de hachages


Les cls de hachage sont stockes en interne comme des chanes.8 Si vous essayez de stocker une rfrence dans un hachage, la valeur de la cl sera convertie en chane :
$x{ \$a } = $a; ($cle, $valeur) = each %x; print $$cle;

# FAUX

Nous avons mentionn plus tt que vous ne pouvez pas reconvertir une chane en rfrence en dur. Si vous essayez de drfrencer $cle qui contient une simple chane, vous ne rcuprerez pas une rfrence en dur, mais simplement un drfrencement symbolique. Et comme vous navez pas de variable nomme SCALAR(0x1fc0e), vous nobtiendrez pas ce que vous voulez. Vous devriez plutt essayer quelque chose comme ceci :
$r = \@a; $x{ $r } = $r;

Comme cela vous pourrez au moins utiliser la valeur du hachage, qui sera une rfrence en dur, au lieu de la cl qui nen est pas une. Bien que vous ne puissiez pas stocker une rfrence en tant que cl, si vous utilisez une rfrence en dur dans un contexte de chane (comme dans lexemple prcdent), vous tes certain que cela produira une chane unique, puisque ladresse de la rfrence fait partie de la chane retourne. Vous pouvez donc utiliser une rfrence comme cl dun hachage. Seulement vous ne pourrez pas la drfrencer par la suite. Il existe un cas particulier de hachage dans lequel vous pouvez utiliser des rfrences comme cls. Par la magie9 du module Tie::RefHash fourni avec Perl, vous pouvez faire ce que nous venons juste de dire que vous ne pouviez pas faire :
use Tie::RefHash; tie my %h, Tie::RefHash; %h = ( ["ceci", "ici"] => " la maison", ["cela", "l-bas"] => "ailleurs", ); while ( my($refcle, $valeur) = each %h ) { print "@$refcle is $valeur\n"; }

En fait, en liant des implmentations diffrentes aux types prdfinis, vous pouvez faire se comporter des scalaires, des hachages et des tableaux de beaucoup de manires dont nous vous avions dit que ctait impossible. a nous apprendra, imbciles dauteurs... Pour en savoir plus sur les liens avec tie, voir le chapitre 14, Variables lies.

8. Elles sont galement stockes en externe comme des chanes, par exemple quand vous les stockez dans des fichiers DBM. En fait, les fichiers DBM imposent que leurs cls (et valeurs) soient des chanes. 9. Oui, cest un terme technique, comme vous vous en rendrez compte si vous fouillez un peu dans le fichier mg.c dans les sources de Perl.

customer_8566

244

Chapitre 8 Rfrences

Ramasse-miettes, rfrences circulaires et rfrences faibles


Les langages de haut niveau permettent aux programmeurs de ne pas sinquiter de la libration de la mmoire quand ils ont fini de lutiliser. Ce procd de rcupration automatique de la mmoire sappelle en franais le ramassage des miettes (en anglais garbage collecting ou collecte des ordures). Dans la plupart des cas, Perl se sert dun mcanisme simple et rapide de ramasse miettes fond sur le comptage de rfrences. Quand on sort dun bloc, ses variables porte locale sont normalement libres, mais il est possible de cacher vos miettes de faon ce que le ramasse miettes de Perl ne puisse les trouver. Un problme srieux est que de la mmoire inatteignable avec un dcompte de rfrences non nul ne sera normalement pas libre. Cest pourquoi les rfrences circulaires sont une mauvaise ide :
{ my ($a, $b); $a = \$b; $b = \$a; } # fait pointer $a et $b lun sur lautre

ou plus simplement :
{ my $a; $a = \$a; } # fait pointer $a sur lui-mme

Bien que $a doive tre dsallou la fin du bloc, en fait il ne lest pas. Quand vous construisez des structures de donnes rcursives, il vous faudra casser (ou affaiblir, voir plus loin) lautorfrence vous-mme si vous voulez que la mmoire soit rcupre avant la fin de votre programme (ou de votre thread). ( la sortie, la mmoire sera automatiquement rcupre pour vous par un mcanisme coteux mais complet de ramasse-miettes par marquage et balayage.) Si la structure de donnes est un objet, vous pouvez utiliser la mthode DESTROY pour casser automatiquement la rfrence ; voir Ramasse-miettes avec les mthodes DESTROY au chapitre 12. Une situation similaire peut se produire avec les caches des entrepts de donnes conus pour une rcupration plus rapide que la normale. Hors du cache on trouve des rfrences donnes lintrieur du cache. Le problme se produit quand toutes ces rfrences sont effaces, mais que les donnes du cache et les rfrences internes restent. Lexistence dune rfrence empche Perl de rcuprer le rfrent, mme si nous voulons que les donnes du cache disparaissent ds quelles ne sont plus utiles. Comme pour les rfrences circulaires, nous vous une rfrence qui naffecte pas le compte de rfrences, et donc ne retarde pas le ramasse-miettes. Les rfrences faibles rsolvent les problmes causs par les rfrences circulaires en vous permettant d affaiblir nimporte quelle rfrence ; cest--dire lui permettre de ne pas modifier le compte des rfrences. Quand la dernire rfrence non faible un objet est dtruite, lobjet est dtruit et toutes les rfrences faibles sont automatiquement libres. Pour utiliser cette fonctionnalit, vous aurez besoin du module WeakRef disponible sur CPAN qui contient une documentation complmentaire. Les rfrences faibles sont une fonctionnalit exprimentale. Mais il faut bien que quelquun serve de cobaye.

customer_8566

Structures de donnes

Perl fournit gratuitement beaucoup des structures de donnes que vous devez construire vous-mme dans dautres langages de programmation. Les piles et et les files que les informaticiens en herbe apprennent en cours ne sont que des tableaux en Perl. Quand vous faites push et pop (ou shift et unshift) sur un tableau, cest une pile ; quand vous faites push et shift (ou unshift et pop) sur un tableau, cest une file. Beaucoup de structures arborescentes dans le monde sont construites pour fournir un accs rapide et dynamique une table de consultation conceptuellement plate. Bien sr, les hachages font partie de Perl et ils fournissent un accs rapide et dynamique une table de consultation conceptuellement plate. Tout cela sans les abrutissantes structures de donnes que trouvent magnifiques ceux dont les esprits ont dj t convenablement abrutis. Mais parfois vous avez besoin de structures de donnes imbriques parce quelle modlisent naturellement le problme que vous essayez de rsoudre. Perl vous permet alors de combiner et demboter des tableaux et des hachages de manire crer des structures de donnes aussi complexes que vous voulez. Quand ils sont utiliss correctement, ils peuvent servir crer des listes chanes, des arbres binaires, des tas, des arbres-B, des ensembles, des graphes et tout ce que vous pouvez imaginer dautre. Voir Mastering Algorithms with Perl (OReilly, 1999), Perl en action (OReilly, France, 1999)1, ou CPAN qui sert de dpt central pour tout ce genre de modules. Mais vous naurez peut-tre jamais besoin que de simples combinaisons de tableaux et de hachages, aussi est-ce ce dont nous allons parler dans ce chapitre.

Tableaux de tableaux
Il existe de nombreuses sortes de structures de donnes. La plus simple construire est le tableau de tableaux, aussi appel matrice deux dimensions. (Ceci se gnralise de manire vidente : un tableau de tableaux de tableaux est une matrice trois dimensions, et ainsi de suite pour les dimensions suprieures.) Cest relativement simple
1. Perl Cookbook (OReilly, 1998) pour la version originale.

customer_8566

246

Chapitre 9 Structures de donnes

comprendre, et presque tout ce qui sapplique dans ce cas sappliquera aussi aux structures plus compliques que nous explorerons dans les sections suivantes.

Cration et accs un tableau deux dimensions


Voici comment construire un tableau deux dimensions :
# Affecte une liste de rfrences de tableaux un tableau @TdT = ( [ "fred", "barney" ], [ "george", "jane", "elroy" ], [ "homer", "marge", "bart" ], ); print $TdT[2][1]; # affiche "marge"

La liste complte est entoure par des parenthses et non par des crochets car vous faites une affectation une liste et non une rfrence. Si vous prfriez une rfrence, vous utiliseriez des crochets :
# Cre une rfrence un tableau de rfrences. $ref_a_TdT = [ [ "fred", "barney", "pebbles", "bamm bamm", "dino", ], [ "homer", "bart", "marge", "maggie", ], [ "george", "jane", "elroy", "judy", ], ]; print $ref_a_TdT->[2][3]; # affiche "judy"

Rappelez-vous quil y a un -> implicite entre deux accolades ou crochets adjacents. Ces deux lignes :
$TdT[2][3] $ref_a_TdT->[2][3]

sont donc quivalentes aux deux lignes suivantes :


$TdT[2]->[3] $ref_a_TdT->[2]->[3]

Il ny a cependant aucun -> implicite avant la premire paire de crochets, cest pourquoi le drfrencement de $ref_a_TdT ncessite le -> initial. Noubliez pas que vous pouvez aussi compter partir de la fin dun tableau avec un indice ngatif, donc :
$TdT[0][-2]

est lavant-dernier lment de la premire ligne.

Volez de vos propres ailes


Ces grosses affectations de listes sont belles et bonnes pour crer une structure de donnes fixe, mais comment faire si vous voulez construire chaque lment au vol ou construire la structure au coup par coup ? Lisons une structure de donnes partir dun fichier. Nous supposerons quil sagit dun fichier texte, o chaque ligne est une range de la structure et est compose dlments

customer_8566

Tableaux de tableaux
spars par des blancs. Voici comment procder :2

247

while (<>) { @tmp = split; # Splite les lments dans un tableau push @TdT, [ @tmp ]; # Ajoute une rfrence de tableau anonyme @TdT }

Bien sr, vous navez pas besoin de donner un nom au tableau temporaire et vous pourriez donc aussi crire :
while (<>) { push @TdT, [ split ]; }

Si vous voulez une rfrence un tableau de tableaux, vous pouvez procder ainsi :
while (<>) { push @$ref_a_TdT, [ split ]; }

Ces deux exemples ajoutent de nouvelles lignes au tableau de tableaux. Comment faire pour ajouter de nouvelles colonnes ? Si vous ne travaillez quavec des tableaux deux dimensions, il est souvent plus facile dutiliser une affectation simple :3
for $x (0 .. 9) { for $y (0 .. 9) { $TdT[$x][$y] = func($x, $y); } } for $x ( 0..9 ) { $ref_a_TdT->[$x][3] = func2($x); } # Pour chaque ligne... # Pour chaque colonne... # ...affecte cette valeur

# Pour chaque ligne... # ...affecte la quatrime colonne

Lordre dans lequel vous affectez les lments na pas dimportance, pas plus que le fait que les lments indics de @TdT existent dj ou non ; Perl les crera pour vous si besoin est en mettant les lments intermdiaires la valeur indfinie. (Perl crera mme la rfrence initiale dans $ref_a_TdT pour vous sil le faut.) Si vous voulez juste ajouter des lments au bout dune ligne, vous devrez faire quelque chose dun peu plus trange :
# Ajoute de nouvelles colonnes une ligne existante. push @{ $TdT[0] }, "wilma", "betty";

Remarquez que ceci ne marcherait pas :


push $TdT[0], "wilma", "betty"; # FAUX !

Cela ne compilerait mme pas, car largument de push doit tre un vritable tableau, et pas seulement une rfrence un tableau. Cest pourquoi le premier argument doit absolument commencer par un caractre @. Ce qui suit le @ est assez ngociable.
2. Ici comme dans dautres chapitres, nous omettons (pour la clart des exemples) les dclarations my que vous devriez normalement mettre. Dans cet exemple, vous devriez crire my @tmp = split. 3. Comme avec laffectation temporaire prcdente, nous avons simplifi ; les boucles de ce chapitre seraient trs probablement crites for my $x dans du code rel.

customer_8566

248

Chapitre 9 Structures de donnes

Utilisation et affichage
Affichons maintenant la structure de donnes. Si vous ne voulez quun seul lment, ceci suffit :
print $TdT[3][2];

Mais si vous voulez tout imprimer, vous ne pouvez pas vous contenter dcrire :
print @TdT; # FAUX

Cest incorrect car vous aurez des rfrences sous forme de chanes de caractres au lieu de vos donnes. Perl ne drfrence jamais automatiquement votre place. Il vous faut donc construire une boucle ou deux. Le code qui suit affiche la structure complte, en bouclant sur les lments de @TdT et en les drfrenant chacun lintrieur de linstruction print :
for $ligne ( @TdT ) { print "@$ligne\n"; }

Pour garder la trace des indices, vous pouvez faire comme ceci :
for $i ( 0 .. $#TdT ) { print "La ligne $i est : @{$TdT[$i]}\n"; }

ou mme cela (remarquez la boucle intrieure) :


for $i ( 0 .. $#TdT ) { for $j ( 0 .. $#{$TdT[$i]} ) { print "Llment $i $j est $AoA[$i][$j]\n"; } }

Comme vous pouvez le voir, les choses se compliquent. Cest pourquoi il est parfois plus simple dutiliser une variable temporaire en cours de route :
for $i ( 0 .. $#TdT ) { $ligne = $TdT[$i]; for $j ( 0 .. $#{$ligne} ) { print "Llment $i $j est $ligne->[$j]\n"; } }

Tranches
Si vous voulez accder une tranche (une partie de ligne) dun tableau multidimensionnel, vous allez devoir faire des indexations subtiles. Loprateur f lche nous donne une faon simple daccder un lment unique, mais rien de tel nexiste pour les tranches. Vous pouvez toujours extraire les lments de votre tranche un par un avec une boucle :
@partie = (); for ($y = 7; $y < 13; $y++) { push @partie, $TdT[4][$y]; }

customer_8566

Tableaux de tableaux
Cette boucle particulire pourrait tre remplace par une tranche de tableau :
@partie = @{ $TdT[4] } [ 7..12 ];

249

Si vous voulez une tranche deux dimensions, par exemple, avec $x dans lintervalle 4..8 et $y dans 7..12, voici une manire de procder :
@nouveauTdT = (); for ($startx = $x = 4; $x <= 8; $x++) { for ($starty = $y = 7; $y <= 12; $y++) { $nouveauTdT[$x - $startx][$y - $starty] = $TdT[$x][$y]; } }

Dans cet exemple, les valeurs individuelles dans notre tableau darrive deux dimensions, @nouveauTdT, sont affectes une par une partir dun sous-tableau deux dimensions de @TdT. Une autre possibilit consiste crer des tableaux anonymes, chacun dentre eux tant constitu de la tranche dsire dun sous-tableau de @TdT, puis mettre des rfrences ces tableaux anonymes dans @nouveauTdT. Nous pourrions alors stocker les rfrences dans @nouveauTdT (index une seule fois, pour ainsi dire) au lieu de stocker des valeurs de sous-tableau dans un @nouveauTdT index deux fois. Cette mthode limine la boucle intrieure :
for ($x = 4; $x <= 8; $x++) { push @nouveauTdT, [ @{ $TdT[$x] } [ 7..12 ] ]; }

Bien sr, si vous faites cela souvent, vous devriez probablement crire un sous-programme appel par exemple extraire_rectangle. Et si vous faites cela trs souvent avec de grandes sries de donnes multidimensionnelles, vous devriez probablement utiliser le module PDL (Perl Data Language), disponible sur CPAN.

Erreurs frquentes
Comme nous lavons dj mentionn, les tableaux et les hachages de Perl sont une dimension. En Perl, mme les tableaux multidimensionnels sont en fait une dimension, mais les valeurs le long de cette dimension sont des rfrences dautres tableaux, qui agrgent plusieurs lments en un seul. Si vous affichez ces valeurs sans les drfrencer, vous obtiendrez les rfrences converties en chanes en lieu et place des donnes dsires. Par exemple ces deux lignes :
@TdT = ( [2, 3], [4, 5, 7], [0] ); print "@TdT";

donneront quelque chose comme :


ARRAY(0x83c38) ARRAY(0x8b194) ARRAY(0x8b1d0)

Dun autre ct, cette ligne affiche 7 :


print $TdT[1][2];

Quand vous construisez un tableau de tableaux, noubliez pas de crer de nouvelles rfrences pour les sous-tableaux. Sinon, vous vous contenterez de crer un tableau contenant le nombre dlments des sous-tableaux, comme ceci :

customer_8566

250
for $i (1..10) { @tableau = fonction($i); $TdT[$i] = @tableau; }

Chapitre 9 Structures de donnes

# FAUX !

Ici on accde @tableau en contexte scalaire, ce qui renvoie donc le nombre de ses lments, lequel est affect comme il se doit $TdT[$i]. La manire correcte daffecter la rfrence vous sera montre dans un moment. Aprs avoir fait lerreur prcdente, les gens ralisent quils doivent affecter une rfrence. Lerreur quils font naturellement ensuite implique de prendre et reprendre une rfrence vers toujours le mme emplacement mmoire :
for $i (1..10) { @tableau = fonction($i); $TdT[$i] = \@tableau; }

# ENCORE FAUX !

Chaque rfrence gnre par la seconde ligne de la boucle for est la mme, cest--dire une rfrence au seul tableau @tableau. Certes, ce tableau change effectivement chaque passage dans la boucle, mais quand tout est fini, $TdT contient 10 rfrences au mme tableau, qui contient maintenant la dernire srie de valeurs qui lui ont t affectes. print @{$TdT[1]} prsentera les mmes valeurs que print @{$TdT[2]}. Voici une approche qui aura plus de succs :
for $i (1..10) { @tableau = fonction($i); $TdT[$i] = [ @tableau ]; }

# CORRECT !

Les crochets autour de @tableau crent un nouveau tableau anonyme, dans lequel les lments de @tableau sont copis. Nous stockons ensuite une rfrence ce nouveau tableau. Un rsultat similaire, bien que beaucoup plus difficile lire, pourra tre obtenu par :
for $i (1..10) { @tableau = fonction($i); @{$TdT[$i]} = @tableau; }

Comme $TdT[$i] doit tre une nouvelle rfrence, la rfrence se met exister. Le @ qui prcde drfrence alors cette nouvelle rfrence, avec pour rsultat daffecter (en contexte de liste) les valeurs de @tableau au tableau rfrenc par $TdT[$i]. Pour des raisons de clart, vous pouvez prfrer viter cette construction. Mais il existe une situation dans laquelle vous voudrez lutiliser. Supposons que @TdT est dj un tableau de rfrences des tableaux. Cest--dire que vous avez fait des affectations comme :
$TdT[3] = \@tableau_original;

Et supposons maintenant que vous vouliez modifier @tableau_original (cest--dire que vous voulez modifier la quatrime ligne de $TdT) de faon ce quil rfre aux lments de @tableau. Ce code fonctionnera :
@{$TdT[3]} = @tableau;

customer_8566

Tableaux de tableaux

251

Dans ce cas, la rfrence ne change pas, mais les lments du tableau rfrenc changent. Cela crase les valeurs de @tableau_original. Finalement, ce code dangereux en apparence fonctionne parfaitement :
for $i (1..10) { my @tableau = fonction($i); $TdT[$i] = \@tableau; }

Cest parce que la variable porte lexicale my @tableau est recre compltement chaque passage dans la boucle. Bien que vous ayez limpression davoir stock une rfrence la mme variable chaque fois, ce nest en fait pas le cas. Cest une subtile distinction, mais cette technique peut produire du code plus efficace, au risque de tromper les programmeurs moins clairs. (Cest plus efficace car il ny a pas de copie dans la dernire affectation.) Dun autre ct, sil vous faut de toute faon copier les valeurs (ce que fait la premire affectation de la boucle), vous pouvez aussi bien utiliser la copie implique par les crochets et viter la variable temporaire :
for $i (1..10) { $TdT[$i] = [ fonction($i) ]; }

En rsum :
$TdT[$i] = [ @tableau ]; $TdT[$i] = \@tableau; @{ $TdT[$i] } = @tableau; # # # # Plus sr, parfois plus rapide Rapide mais risqu, dpend du ct "my" de @tableau Un peu rus

Une fois que vous matrisez les tableaux de tableaux, vous voudrez vous mesurer des structures de donnes plus complexes. Si vous cherchez les structures (struct) de C ou les enregistrements (record) de Pascal, vous ne trouverez aucun mot rserv en Perl qui en crera pour vous. Ce que vous avez en revanche est un systme plus f lexible. Si votre ide dune structure est moins f lexible que cela, ou si vous voulez fournir vos utilisateurs quelque chose de plus rigide et de plus opaque, alors vous pouvez utiliser les fonctionnalits orientes objet dtailles au chapitre 12, Objets. Perl dispose de deux manires dorganiser les donnes : comme des listes ordonnes dans des tableaux, dont laccs aux lments se fait par leur position, ou comme des listes non ordonnes de couples cl/valeur stocks dans des hachages et auxquels on accde par leur nom. La meilleure faon de reprsenter un enregistrement en Perl consiste utiliser une rfrence de hachage, mais la manire dorganiser de tels enregistrements peut varier. Si vous dsirez conserver une liste ordonne de ces enregistrements et y accder par leur numro, vous utiliserez un tableau de rfrences de hachages pour stocker les enregistrements. Ou bien, si vous prfrez accder ces enregistrements par leurs noms, vous maintiendrez un hachage de rfrences des hachages. Vous pourriez mme faire les deux la fois avec un pseudo-hachage. Dans les sections suivantes, vous trouverez des exemples de code dcrivant comment composer ( partir de rien), gnrer (depuis dautres sources), accder et afficher plusieurs structures de donnes diffrentes. Nous montrerons dabord trois combinaisons videntes de hachages et de tableaux, suivies par un hachage de fonctions puis des structures de donnes plus irrgulires. Nous terminerons par la prsentation dune manire

customer_8566

252

Chapitre 9 Structures de donnes

de sauver ces structures de donnes. Ces exemples supposent que vous vous tes dj familiaris avec les explications qui prcdent dans ce chapitre.

Hachages de tableaux
Utilisez un hachage de tableaux quand vous voulez accder chaque tableau par une chane particulire plutt que par un numro dindice. Dans notre exemple de personnages dmissions de tlvision, au lieu de parcourir la liste de noms partir de la zroime mission, la premire et ainsi de suite, nous allons mettre en place notre structure de faon pouvoir obtenir la liste des personnages partir du nom du dessin anim. Comme notre structure de donnes est un hachage, nous ne pouvons pas en ordonner le contenu, mais nous pouvons utiliser la fonction sort pour spcifier un ordre de sortie particulier.

Composition dun hachage de tableaux


Vous pouvez crer un hachage de tableaux anonymes comme suit :
# Nous omettons habituellement les guillemets quand les cls sont # des identificateurs. %HdT = ( flintstones => [ "fred", "barney" ], jetsons => [ "george", "jane", "elroy" ], simpsons => [ "homer", "marge", "bart" ], );

Pour ajouter un nouveau tableau au hachage, vous pouvez simplement crire :


$HdT{teletubbies} = [ "tinky winky", "dipsy", "laa-laa", "po" ];

Gnration dun hachage de tableaux


Voici quelques techniques pour remplir un hachage de tableaux. Pour le lire partir dun fichier avec le format suivant :
flintstones: fred barney wilma dino jetsons: george jane elroy simpsons: homer marge bart

vous pourriez utiliser lune des deux boucles suivantes :


while ( <> ) { next unless s/^(.*?):\s*//; $HdT{$1} = [ split ]; } while ( $ligne = <> ) { ($qui, $reste) = split /:\s*/, $ligne, 2; @champs = split , $reste; $HdT{$qui} = [ @champs ]; }

customer_8566

Hachages de tableaux

253

Si vous avez un sous-programme get_famille qui renvoie un tableau, vous pouvez vous en servir pour remplir %HdT avec lune de ces deux boucles :
for $groupe ( "simpsons", "jetsons", "flintstones" ) { $HdT{$groupe} = [ get_famille($groupe) ]; } for $groupe ( "simpsons", "jetsons", "flintstones" ) { @membres = get_famille($groupe); $HdT{$groupe} = [ @membres ]; }

Vous pouvez ajouter de nouveaux membres un tableau existant comme ceci :


push @{ $HdT{flintstones} }, "wilma", "pebbles";

Utilisation et affichage dun hachage de tableaux


Vous pouvez fixer le premier lment dun tableau en particulier comme suit :
$HdT{flintstones}[0] = "Fred";

Pour mettre en majuscule linitiale du deuxime Simpson, appliquez une substitution llment de tableau appropri :
$HdT{simpsons}[1] =~ s/(\w)/\u$1/;

Vous pouvez afficher toutes les familles en bouclant sur toutes les cls du hachage :
for $famille ( keys %HdT ) { print "$famille : @{ $HdT{$famille} }\n"; }

Avec un petit effort supplmentaire, vous pouvez galement ajouter les indices de tableau :
for $famille ( keys %HoA ) { print "$famille : "; for $i ( 0 .. $#{ $HdT{$famille} } ) { print " $i = $HdT{$famille}[$i]"; } print "\n"; }

Ou trier les tableaux par leur nombre dlments :


for $famille ( sort { @{$HdT{$b}} <=> @{$HdT{$a}} } keys %HdT ) { print "$famille : @{ $HdT{$famille} }\n" }

Ou mme trier les tableaux par leur nombre dlments puis trier les lments ASCIIbtiquement (ou pour tre prcis, utf8-tiquement ) :
# Affiche lensemble tri par le nombre de personnes et leurs noms. for $famille ( sort { @{$HdT{$b}} <=> @{$HdT{$a}} } keys %HdT ) { print "$famille : ", join(", ", sort @{ $HdT{$famille} }), "\n"; }

customer_8566

254

Chapitre 9 Structures de donnes

Tableaux de hachages
Un tableau de hachages est utile quand vous avez un tas denregistrements auxquels vous aimeriez accder squentiellement et que chaque enregistrement comporte des couples cl/valeur. Les tableaux de hachages sont moins frquemment utiliss que les autres structures de ce chapitre.

Composition dun tableau de hachages


Vous pouvez crer un tableau de hachages anonymes comme suit :
@TdH = ( { mari femme fils }, { mari femme fils }, { mari femme fils }, );

=> "barney", => "betty", => "bamm bamm",

=> "george", => "jane", => "elroy",

=> "homer", => "marge", => "bart",

Pour ajouter un nouveau hachage au tableau, vous pouvez simplement crire :


push @TdH, { mari => "fred", femme => "wilma", fille => "pebbles" };

Gnration dun tableau de hachages


Voici quelques techniques pour remplir un tableau de hachages. Pour lire depuis un fichier crit selon le format suivant :
mari=fred ami=barney

vous pourriez utiliser lune des deux boucles suivantes :


while ( <> ) { $enrt = {}; for $champ ( split ) { ($cle, $valeur) = split /=/, $champ; $enrt->{$cle} = $valeur; } push @TdH, $enrt; }

customer_8566

Hachages de hachages
while ( <> ) { push @TdH, { split /[\s=]+/ }; }

255

Si vous avez un sous-programme get_paire_suivante qui renvoie des couples cl/valeur, vous pouvez lutiliser pour remplir @TdH avec lun de ces deux boucles :
while ( @champs = get_paire_suivante() ) { push @TdH, { @champs }; } while (<>) { push @TdH, { get_paire_suivante($_) }; }

Vous pouvez ajouter de nouveaux lments un hachage existant comme ceci :


$TdH[0]{animal} = "dino"; $TdH[2]{animal} = "petit papa Nol";

Utilisation et affichage dun tableau de hachages


Vous pouvez modifier un couple cl/valeur dun hachage particulier comme suit :
$TdH[0]{mari} = "fred";

Pour mettre en majuscule le mari du deuxime hachage appliquez une substitution :


$TdH[1]{mari} =~ s/(\w)/\u$1/;

Vous pouvez afficher toutes les donnes comme suit :


for $href ( @TdH ) { print "{ "; for $role ( keys %$href ) { print "$role=$href->{$role} "; } print "}\n"; }

et avec les indices :


for $i ( 0 .. $#TdH ) { print "$i est { "; for $role ( keys %{ $TdH[$i] } ) { print "$role=$TdH[$i]{$role} "; } print "}\n"; }

Hachages de hachages
Le hachage multidimensionnel est la plus souple des structures embotes de Perl. Cela revient construire un enregistrement qui contient dautres enregistrement Vous indexez chaque niveau avec des chanes (entre guillemets si besoin est). Souvenez vous cependant que les couples cl/valeur du hachage ne sortiront dans aucun ordre particu-

customer_8566

256

Chapitre 9 Structures de donnes

lier ; vous pouvez utiliser la fonction sort pour rcuprer les couples dans lordre qui vous intresse.

Composition dun hachage de hachage


Vous pouvez crer un hachage de hachages anonymes comme suit :
%HdH = ( flintstones => { mari => pote => }, jetsons => { mari => femme => "son fils"=> }, simpsons => { mari => femme => fiston => }, );

"fred", "barney",

"george", "jane", "elroy", # Guillemets ncessaires sur la cl

"homer", "marge", "bart",

Pour ajouter un autre hachage anonyme %HdH, vous pouvez simplement crire :
$HdH{ mash } = { capitaine => "pierce", major => "burns", caporal => "radar", };

Gnration dun hachage de hachages


Voici quelques techniques pour remplir un hachage de hachages. Pour lire des donnes partir dun fichier dans le format suivant :
flintstones: mari=fred pote=barney femme=wilma animal=dino

vous pourriez utiliser lune des deux boucles suivantes :


while ( <> ) { next unless s/^(.*?):\s*//; $qui = $1; for $champ ( split ) { ($cle, $valeur) = split /=/, $champ; $HdH{$qui}{$cle} = $valeur; } } while ( <> ) { next unless s/^(.*?):\s*//; $qui = $1;

customer_8566

Hachages de hachages
$enrt = {}; $HdH{$qui} = $enrt; for $champ ( split ) { ($cle, $valeur) = split /=/, $champ; $enrt->{$cle} = $valeur; } }

257

Si vous avez un sous-programme get_famille qui renvoie une liste de couples cl/valeur, vous pouvez vous en servir pour remplir %HdH avec lun de ces trois bouts de code :
for $groupe ( "simpsons", "jetsons", "flintstones" ) { $HdH{$groupe} = { get_famille($groupe) }; } for $groupe ( "simpsons", "jetsons", "flintstones" ) { @membres = get_famille($groupe); $HdH{$groupe} = { @membres }; } sub hash_familles { my @ret; for $groupe ( @_ ) { push @ret, $groupe, { get_famille($groupe) }; } return @ret; } %HdH = hash_familles( "simpsons", "jetsons", "flintstones" );

Vous pouvez ajouter de nouveaux membres un hachage comme suit :


%nouveaux = ( femme => "wilma", animal => "dino"; ); for $quoi (keys %nouveaux) { $HdH{flintstones}{$quoi} = $nouveaux{$quoi}; }

Utilisation et affichage dun hachage de hachages


Vous pouvez modifier un couple cl/valeur dun hachage particulier comme suit :
$HdH{flintstones}{femme} = "wilma";

Pour mettre en majuscule la valeur associe une cl particulire, appliquez une substitution un lment :
$HdH{jetsons}{son fils} =~ s/(\w)/\u$1/;

Vous pouvez afficher toutes les familles en bouclant sur les cls du hachage externe, puis en bouclant sur les cls du hachage interne :
for $famille ( keys %HdH ) { print "$famille : ";

customer_8566

258

Chapitre 9 Structures de donnes


for $role ( keys %{ $HdH{$famille} } ) { print "$role=$HdH{$famille}{$role} "; } print "\n";

Dans les hachages trs grands, il peut tre un peu plus rapide de rcuprer la fois les cls et les valeurs en utilisant each (ce qui exclut le tri) :
while ( ($famille, $roles) = each %HdH ) { print "$famille : "; while ( ($role, $personne) = each %$roles ) { print "$role=$personne "; } print "\n"; }

(Hlas, ce sont les grands hachages qui ont vraiment besoin dtre tris, sinon vous ne trouverez jamais ce que vous cherchez dans ce qui est affich.) Vous pouvez trier les familles, puis les rles, comme suit :
for $famille ( sort keys %HdH ) { print "$famille : "; for $role ( sort keys %{ $HdH{$famille} } ) { print "$role=$HdH{$famille}{$role} "; } print "\n"; }

Pour trier les familles par leur nombre de membres (plutt quASCII-btiquement (ou utf8-tiquement)), vous pouvez utiliser keys en contexte scalaire :
for $famille ( sort { keys %{$HdH{$a}} <=> keys %{$HdH{$b}} } keys %HdH ) { print "$famille : "; for $role ( sort keys %{ $HdH{$famille} } ) { print "$role=$HdH{$family}{$role} "; } print "\n"; }

Pour trier les membres dune famille dans un certain ordre, vous pouvez leur donner chacun un rang :
$i = 0; for ( qw(mari femme fils fille pote animal) ) { $rang{$_} = ++$i } for $famille ( sort { keys %{$HdH{$a}} <=> keys %{$HdH{$b}} } keys %HdH ) { print "$famille : "; for $role ( sort { $rang{$a} <=> $rang{$b} } keys %{ $HdH{$famille} } ) { print "$role=$HdH{$famille}{$role} "; } print "\n"; }

customer_8566

Hachages de fonctions

259

Hachages de fonctions
Quand vous crivez une application complexe ou un service rseau en Perl, vous voulez probablement mettre un grand nombre de commandes la disposition de vos utilisateurs. Un tel programme pourrait avoir du code comme celui-ci pour examiner le choix de lutilisateur et agir en consquence :
if ($cmd =~ /^exit$/i) elsif ($cmd =~ /^help$/i) elsif ($cmd =~ /^watch$/i) elsif ($cmd =~ /^mail$/i) elsif ($cmd =~ /^edit$/i) elsif ($cmd =~ /^delete$/i) else { warn "Commande inconnue : } { { { { { { exit } show_help() } $watch = 1 } mail_msg($msg) } $edited++; editmsg($msg); } confirm_kill() }

$cmd; Essayez help la prochaine fois\n";

Vous pouvez galement stocker des rfrences des fonctions dans vos structures de donnes, tout comme vous pouvez y stocker des tableaux ou des hachages :
%HdF = ( exit help watch mail edit delete ); # Compose un hachage de fonctions => sub { exit }, => \&show_help, => sub { $watch = 1 }, => sub { mail_msg($msg) }, => sub { $edited++; editmsg($msg); }, => \&confirm_kill,

if ($HdF{lc $cmd}) { $HdF{lc $cmd}->() } # Appelle la fonction else { warn "Commande inconnue : $cmd; Essayez help la prochaine fois\n" }

Dans lavant-dernire ligne, nous vrifions si le nom de commande spcifi (en minuscules) existe dans notre table de distribution %HdF. Si cest le cas, nous appelons la commande approprie en drfrenant la valeur du hachage comme une fonction et passons cette fonction une liste darguments vide. Nous pourrions aussi lavoir drfrence comme &{ $HoF{lc $cmd} }(), ou partir de la version 5.6 de Perl, simplement par $HoF{lc $cmd}().

Enregistrements plus labors


Jusquici nous avons vu dans ce chapitre des structures de donnes simples, homognes et deux niveaux : chaque lment contient le mme genre de rfrent que tous les autres lments de ce niveau. Ce nest pas indispensable. Tout lment peut contenir nimporte quel type de scalaire, ce qui signifie quil peut sagir dun chane, dun nombre ou dune rfrence nimporte quoi dautre. La rfrence peut tre une rfrence un tableau ou un hachage, ou un pseudo-hachage, ou une rfrence une fonction nomme ou anonyme, ou un objet. La seule chose que vous ne pouvez pas faire est de mettre plusieurs rfrents dans un seul scalaire. Si vous vous retrouvez essayer de faire ce genre de chose, cest le signe que vous avez besoin dune rfrence un tableau ou un hachage pour superposer plusieurs valeurs en une seule.

customer_8566

260

Chapitre 9 Structures de donnes

Dans les sections qui suivent, vous trouverez des exemples de code destins montrer ce quil est possible de stocker dans un enregistrement, que nous implmenterons comme une rfrence un hachage. Les cls sont en majuscules, une convention parfois employe quand le hachage est utilis comme un type denregistrement spcifique.

Composition, utilisation et affichage denregistrements plus labors


Voici un enregistrement avec six champs de types diffrents :
$enrt = { TEXTE SEQUENCE RECHERCHE CODE1 CODE2 HANDLE }; => => => => => => $chaine, [ @anc_valeurs ], { %une_table }, \&une_fonction, sub { $_[0] ** $_[1] }, \*STDOUT,

Le champ TEXTE est une simple chane, que vous pouvez donc afficher :
print $enrt->{TEXT};

SEQUENCE et RECHERCHE sont des rfrences normales un tableau et un hachage :


print $enrt->{SEQUENCE}[0]; $dernier = pop @{ $enrt->{SEQUENCE} }; print $enrt->{RECHERCHE}{"cle"}; ($premier_c, $premier_v) = each %{ $enrt->{RECHERCHE} };

CODE1 est un sous-programme nomm et CODE2 un sous-programme anonyme, mais sont appels de la mme faon :
$reponse1 = $enrt->{CODE1}->($arg1, $arg2); $reponse2 = $enrt->{CODE2}->($arg1, $arg2);

Avec une paire daccolades supplmentaires, pour pouvez traiter $rec->{HANDLE} comme un objet indirect :
print { $enrt->{HANDLE} } "une chane\n";

Si vous utilisez le module FileHandle, vous pouvez mme traiter le handle comme un objet normal :
use FileHandle; $enrt->{HANDLE}->autoflush(1); $enrt->{HANDLE}->print("une chane\n");

Composition, utilisation et affichage denregistrements encore plus labors


Naturellement, les champs de vos structures de donnes peuvent eux-mmes tre des structures de donnes arbitrairement complexes :

customer_8566

Enregistrements plus labors


%TV = ( flintstones => { serie => "flintstones", soirs => [ "lundi", "jeudi", membres => [ { nom => "fred", role => { nom => "wilma", role => { nom => "pebbles", role => ], },

261

"vendredi" ], "mari", age => 36, }, "femme", age => 31, }, "enfant", age => 4, },

jetsons => { serie => "jetsons", soirs => [ "mercredi", "samedi" ], membres => [ { nom => "george", role => "mari", age => 41, }, { nom => "jane", role => "femme", age => 39, }, { nom => "elroy", role => "enfant", age => 9, }, ], }, simpsons => { serie => "simpsons", soirs => [ "lundi" ], membres => [ { nom => "homer", role => "mari", { nom => "marge", role => "femme", { nom => "bart", role => "enfant", ], }, );

age => 34, }, age => 37, }, age => 11, },

Gnration dun hachage denregistrements complexes


Comme Perl est assez bon pour analyser des structures de donnes complexes, pour pouvez aussi bien mettre vos dclarations de donnes dans un fichier spar comme du code Perl normal, puis le charger avec les fonctions intgres do ou require. Une autre approche courante est dutiliser un module de CPAN (comme XML::Parser) pour charger des structures de donnes quelconques crites dans un autre langage (comme XML). Vous pouvez construire vos structures de donnes petit petit :
$enrt = {}; $enrt->{serie} = "flintstones"; $enrt->{soirs} = [ quels_jours() ];

Ou les lire partir dun fichier (quon suppose ici crit sous la forme champ=valeur) :
@membres = (); while (<>) { %champs = split /[\s=]+/; push @membres, { %champs }; }

customer_8566

262
$enrt->{membres} = [ @membres ];

Chapitre 9 Structures de donnes

Puis les inclure dans des structures de donnes plus grandes, indexes par lun des souschamps :
$TV{ $enrt->{serie} } = $enrt;

Vous pouvez utiliser des champs supplmentaires pour viter de dupliquer les donnes. Par exemple, vous pourriez vouloir inclure un champ "enfants" dans lenregistrement dune personne, lequel pourrait tre une rfrence un tableau contenant des rfrences aux propres enregistrements des enfants. En ayant des parties de votre structure de donnes qui pointent sur dautres, vous viter les drives rsultant de la mise jour des donnes un endroit mais pas un autre :
for $famille (keys %TV) { my $enrt = $TV{$famille}; # pointeur temporaire my @enfants = (); for $personne ( @{$enrt->{membres}} ) { if ($personne->{role} =~ /enfant|fils|fille/) { push @enfants, $personne; } } # $enrt et $TV{$famille} pointent sur les mmes donnes ! $enrt->{enfants} = [ @enfants ]; }

Laffectation $enrt->{enfants} = [ @enfants ] copie le contenu du tableau mais ce sont simplement des rfrences des donnes non copies. Cela signifie que si vous modifiez lge de Bart comme suit :
$TV{simpsons}{enfants}[0]{age}++; # incrmente 12

alors vous verrez le rsultat suivant, car $TV{simpsons}{enfants}[0] et $TV{simpsons}{membres}[2] pointent tous deux vers le mme hachage anonyme :
print $TV{simpsons}{membres}[2]{age}; # affiche 12 galement

Et maintenant pour imprimer toute la structure de donnes %TV :


for $famille ( keys %TV ) { print "la famille $famille"; print " passe ", join (" et ", @{ $TV{$famille}{nights} }), "\n"; print "ses membres sont :\n"; for $qui ( @{ $TV{$famille}{membres} } ) { print " $qui->{name} ($qui->{role}), age $qui->{age}\n"; } print "enfants: "; print join (", ", map { $_->{nom} } @{ $TV{$famille}{enfants} } ); print "\n\n"; }

Sauvegarde de structures de donnes


Il existe plusieurs manires de sauver vos structures de donnes pour les utiliser avec un autre programme par la suite. La manire la plus simple consiste utiliser le module

customer_8566

Sauvegarde de structures de donnes

263

Data::Dumper de Perl, qui convertit une structure de donnes (potientiellement autorfrente) en une chane qui peut tre sauve pour tre reconstitue par la suite avec eval ou do.
use Data::Dumper; $Data::Dumper::Purity = 1; # car %TV est autorfrent open (FILE, "> tvinfo.perldata") or die "impossible douvrir tvinfo: $!"; print FILE Data::Dumper->Dump([\%TV], [*TV]); close FILE or die "impossible de fermer tvinfo: $!";

Un autre programme (ou le mme programme) pourra lire le fichier plus tard :
open (FILE, "< tvinfo.perldata") or die "impossible douvrir tvinfo: $!"; undef $/; # lit tout le fichier dun coup eval <FILE>; # recre %TV die "impossible de recrer les donnes depuis tvinfo.perldata: $@" if $@; close FILE or die "impossible de fermer tvinfo: $!"; print $TV{simpsons}{membres}[2]{age};

ou simplement :
do "tvinfo.perldata" or die "impossible de recrer tvinfo: $! $@"; print $TV{simpsons}{membres}[2]{age};

Beaucoup dautres solutions sont disponibles, avec des formats de stockage qui vont des donnes binaires (trs rapide) au XML (trs interoprable). Visitez vite un miroir du CPAN prs de chez vous !

customer_8566

customer_8566

Paquetages

10

Dans ce chapitre, nous allons pouvoir commencer nous amuser, car nous allons aborder la bonne conception des logiciels. Pour ce faire, parlons de Paresse, dImpatience et dOrgueil, les bases de la bonne conception des logiciels. Nous sommes tous tombs dans le pige du copier/coller alors quil fallait dfinir une abstraction de haut niveau, ne serait-ce quune boucle ou une routine simple.1 Il est vrai que certains partent lautre extrme en dfinissant des tas croissants dabstractions de plus haut niveau alors quil aurait suffi dun copier/coller.2 Mais en g7nral, la plupart dentre nous devraient penser employer plus dabstraction plutt que moins. Entre les deux se trouvent ceux qui ont une vision quilibre du degr dabstraction ncessaire, mais qui se lancent dans la conception de leurs propres abstractions alors quils devraient utiliser un code existant.3 Chaque fois que vous tes tent dadopter lune ou lautre de ces attitudes, il vous faut dabord vous asseoir et penser ce qui sera le mieux pour vous et votre prochain long terme. Si vous allez dverser vos nergies cratives dans une masse de code, pourquoi ne pas rendre le monde meilleur pendant que vous y tes ? (Mme si vous ne visez qu russir le programme, vous devez vous assurer quil convient la bonne niche cologique.) La premire tape vers une programmation cologiquement soutenable est simple : pas de dtritus dans le parc. Lorsque vous crivez un bout de code, pensez lui donner son propre espace de noms, de sorte que vos variables et vos fonctions ncrasent pas celles de quelquun dautre, ou vice-versa. Un espace de noms est un peu comme votre maison, dans laquelle il vous est permis dtre aussi dsordonn que vous le voulez, tant que votre interface externe avec les autres citoyens reste un tant soit peu correcte. En Perl, un espace de noms sappelle un paquetage (package). Les paquetages fournissent la bri-

1. Ce qui est une mauvaise forme de Paresse. 2. Ce qui est une forme dOrgueil mal plac. 3. Ce qui, vous lavez devin, est une mauvaise forme dImpatience. Mais si vous voulez vraiment rinventer la roue, essayez au moins den inventer une meilleure.

customer_8566

266

Chapitre 10 Paquetages

que de base sur laquelle les concepts de plus haut niveau de module et de classe sont labors. Tout comme la notion de maison , la notion de paquetage est un peu nbuleuse. Les paquetages sont indpendants des fichiers. On peut aussi bien avoir plusieurs paquetages dans un seul fichier, ou un unique paquetage rparti sur plusieurs fichiers, tout comme votre maison peut tre soit une petite mansarde dans un grand btiment (si vous tes un artiste sans le sou), soit un ensemble de btiments (si votre nom se trouve tre Reine Elizabeth). Mais une maison est habituellement compose dun seul btiment, comme un paquetage est habituellement compos dun seul fichier. Avec Perl, vous pouvez mettre un paquetage dans un seul fichier, tant que vous acceptez de donner au fichier le mme nom que le paquetage et dutiliser lextension .pm, qui est labrviation de perl module . Le module est lunit fondamentale de rutilisation de Perl. En effet, pour utiliser un module, vous vous servez de la commande use, qui est une directive de compilation qui contrle limportation des fonctions et des variables dun module. Chaque exemple de use que vous avez vu jusqu maintenant est un exemple de rutilisation de module. Le Comprehensive Perl Archive Network, ou CPAN, est lendroit o mettre vos modules si dautres personnes pouvaient les trouver utiles. Perl a prospr grce la volont des programmeurs partager les fruits de leur travail avec la communaut. videmment, CPAN est galement lendroit o vous pouvez trouver des modules que dautres ont gentiment tlcharg pour lusage de tous. Voir le chapitre 22, CPAN, et www.cpan.org plus de dtails. Depuis 25 ans environ, il est la mode de concevoir des langages informatiques qui imposent un tat de paranoa. On attend de vous de programmer chaque module comme sil tait en tat de sige. Il existe sans doute certaines cultures fodales au sein desquelles ceci est justifiable, mais toutes les cultures ne sont pas ainsi faites. Dans la culture Perl, par exemple, on attend de vous que vous restiez en dehors de la maison de quelquun parce que vous ny avez pas t invit, et non parce quil y a des barreaux aux fentres.4 Ceci nest pas un livre sur la programmation oriente objet, et nous ne sommes pas l pour vous convertir en fanatique dlirant de lorient objet, mme si justement vous souhaitez tre converti. Il existe dj de nombreux livres disponibles sur ce sujet. La philosophie Perl de la conception oriente objet correspond parfaitement la philosophie Perl de tout le reste ; utilisez la conception oriente objet (OO) l o elle a un sens, et vitez-la l o elle nen a pas. vous de voir. En parler OO, chaque objet appartient un groupement appel classe. En Perl, les classes, les paquetages et les modules sont tellement lis que les dbutants peuvent souvent les considrer interchangeables. Typiquement, une classe est implmente par un module qui dfinit un paquetage ayant le mme nom que la classe. Nous expliquerons cela dans les quelques chapitres qui suivent. Lorsque vous utilisez un module avec use, vous bnficiez de la rutilisation directe de logiciel. Avec les classes, vous bnficiez de la rutilisation indirecte de logiciel lorsquune classe en utilise une autre par hritage. Avec les classes, vous gagnez quelque chose de plus : une interface propre avec un autre espace de noms. On naccde quelque
4. Mais Perl fournit aussi des barreaux si vous le voulez. Voir Gestion des donnes non sres au chapitre 23, Scurit.

customer_8566

Paquetages
chose dans une classe quindirectement, isolant ainsi la classe du monde extrieur.

267

Comme nous lavons indiqu dans le chapitre 8, Rfrences, la programmation oriente objet est ralise par des rfrences dont les rfrents savent quelle classe ils appartiennent. En fait, maintenant que vous connaissez les rfrences, vous connaissez presque tout ce que les objets ont de difficile. Le reste se trouve sous les doigts , comme dirait un pianiste. Mais cependant il va falloir pratiquer un peu. Un de vos exercices de gammes de base consiste apprendre comment protger diffrents bouts de code pour quune partie naltre pas par inadvertance les variables des autres parties. Chaque bout de code appartient un paquetage bien dfini, ce qui dtermine quelles variables et quelles fonctions sont sa disposition. Lorsque Perl rencontre un bout de code, il le compile dans le paquetage courant. Le paquetage courant initial est appel main , mais vous pouvez passer du paquetage courant un autre tout moment avec la dclaration package. Le paquetage courant dtermine quelle table de symboles est utilise pour trouver vos variables, fonctions, handles dentre/sortie, et formats. Toute variable qui nest pas dclare avec my est associe un paquetage mme des variables apparemment omniprsentes comme $_ et %SIG. En fait, les variables globales nexistent pas vraiment en Perl, ce sont simplement des variables de paquetage. (Les identificateurs spciaux comme _ et SIG ne sont quapparemment globaux, car ils sont par dfaut dans le paquetage main plutt que dans le paquetage courant.) La porte dune dclaration package commence la dclaration elle-mme et se termine la fin de la porte qui la contient (bloc, fichier ou eval celle qui arrive en premier) ou jusqu une autre dclaration package au mme niveau, qui remplace la prcdente. (Ceci est une pratique courante.) Tous les identificateurs ultrieurs (dont ceux qui sont dclars avec our, mais non ceux qui sont dclars avec my ou qualifis avec le nom dun autre paquetage) seront placs dans la table de symboles appartenant au paquetage courant. (Les variables dclares avec my sont indpendantes des paquetages. Elles sont toujours visibles lintrieur, et uniquement lintrieur, de la porte les contenant, quelles que soient les dclarations de paquetage.) Une dclaration de paquetage sera habituellement la premire instruction dun fichier destin tre inclus par require ou use. Mais ce nest quune convention. Vous pouvez mettre une dclaration package partout o vous pouvez mettre une instruction. Vous pouvez mme la mettre la fin dun bloc, auquel cas elle naura pas le moindre effet. Vous pouvez passer dun paquetage un autre plus dun endroit, car une dclaration de paquetage ne fait que slectionner la table de symboles utiliser par le compilateur pour le reste de ce bloc. (Cest ainsi quun paquetage donn peut se rpartir sur plusieurs fichiers.) Vous pouvez faire rfrence aux identificateurs5 appartenant dautres paquetages en
5. Par identificateurs, nous dsignons les noms utiliss comme clefs de table de symboles pour accder aux variables scalaires, variables de tableau, variables de hachage, fonctions, handles de fichier ou de rpertoire et formats. Syntaxiquement parlant, les tiquettes sont aussi des identificateurs, mais elles ne sont pas places dans une table de symboles prcise ; elles sont plutt rattaches directement aux instructions de votre programme. Les tiquettes ne peuvent tre qualifies par un paquetage.

customer_8566

268

Chapitre 10 Paquetages

les prfixant ( qualifiant ) avec leur nom de paquetage et un double deux-points : $Paquetage::Variable. Si le nom du paquetage est nul, cest le paquetage principal (main) qui est pris par dfaut. Cest--dire que $::chaude est quivalent $main::chaude. 6 Lancien dlimiteur de paquetage tait lapostrophe, ainsi dans danciens programmes Perl vous verrez des variables comme $mainchaude et $unpackdebiere. Mais le double deux-points est conseill parce quil est plus lisible, dune part pour les humains, et dautre part pour les macros emacs. Il donne aussi aux programmeurs C++ le sentiment quils savent ce qui se passe alors que lapostrophe tait l pour donner aux programmeurs Ada le sentiment de savoir ce qui se passe. Comme la syntaxe dmode est encore supporte pour la compatibilit arrire, si vous essayez dutiliser une chane comme "This is $owners house", vous accderez $owner::s, cest dire la variable $s dans le paquetage owner, ce qui nest probablement pas ce que vous vouliez dire. Utilisez des accolades pour liminer lambigut, par exemple "This is ${owner}s house". Le double deux-points peut tre utilis pour mettre bout bout des identificateurs dans un nom de paquetage : $Rouge::Bleu::var. Ce qui veut dire : le $var appartenant au paquetage Rouge::Bleu. Le paquetage Rouge::Bleu na rien voir avec un quelconque paquetage Rouge ou Bleu existant ventuellement. Une relation entre Rouge::Bleu et Rouge ou Bleu peut avoir un sens pour la personne qui crit ou utilise le programme, mais nen a aucun pour Perl. (Enfin, part le fait que, dans limplmentation actuelle, la table de symboles Rouge::Bleu se trouve tre range dans la table de symboles Rouge. Mais le langage Perl nen fait aucun usage direct.) Pour cette raison, chaque dclaration package doit dclarer un nom de paquetage complet. Aucun nom de paquetage ne sous-entend un quelconque prfixe , mme sil est (apparemment) dclar lintrieur de la porte dune autre dclaration de paquetage. Seuls les identificateurs (les noms commenant par une lettre ou un soulign) sont rangs dans la table de symboles dun paquetage. Tous les autres symboles sont gards dans le paquetage main, notamment toutes les variables non-alphabtiques comme $!, $?, et $_. De plus, lorquils ne sont pas qualifis, les identificateurs STDIN, STDOUT, STDERR, ARGV , ARGVOUT, ENV INC et SIG se trouvent obligatoirement dans le paquetage main, mme lors, quils sont utiliss dautres fins que celles auxquelles ils sont destins par construction. Ne nommez pas votre paquetage m, s, y, tr, q, qq, qr, qw, ou qx sauf si vous cherchez beaucoup dennuis. Par exemple, vous ne pourrez pas utiliser la forme qualifie dun identificateur comme handle de fichier, car il sera interprt au contraire comme une recherche de motif, une substitution ou une translittration. Il y a longtemps, les variables commenant avec un soulign appartenaient obligatoirement au paquetage main, mais nous avons dcid quil tait plus utile pour les crateurs dun paquetage de pouvoir utiliser un soulign en dbut de nom pour indiquer des identificateurs semi-privs destins uniquement lusage interne de ce paquetage. (Des variables rellement prives peuvent tre dclares comme variables lexicales dans la porte dun fichier, mais cela marche le mieux quand un paquetage et un module ont
6. Pour viter un autre sujet de confusion ventuelle, dans le cas dun nom de variable comme $main::chaude, nous utilisons le terme identificateur pour parler de main et de chaude, mais pas de main::chaude, que nous nommons plutt nom de variable, car les identificateurs ne peuvent pas contenir de deux-points.

customer_8566

Tables de symboles
une relation bijective, ce qui est courant mais pas obligatoire.)

269

Le hachage %SIG (qui sert intercepter les signaux, voir le chapitre 16, Communication interprocessus) est galement spcial. Si vous dfinissez un gestionnaire de signal en tant que chane, il est sous-entendu quil fait rfrence une fonction du paquetage main, sauf si le nom dun autre paquetage est explicitement utilis. Qualifiez compltement le nom dun gestionnaire de signal si vous voulez utiliser un paquetage spcifique, ou vitez entirement les chanes en affectant plutt un typeglob ou une rfrence une fonction :
$SIG{QUIT} $SIG{QUIT} $SIG{QUIT} $SIG{QUIT} $SIG{QUIT} = = = = = "Pack::attrape_quit"; # nom de gestionnaire qualifi "attrape_quit"; # sous-entend "main::attrape_quit" *attrape_quit; # impose la fonction du paquetage courant \&attrape_quit; # impose la fonction du paquetage courant sub { print "Attrap SIGQUIT\n" }; # fonction anonyme

La notion de paquetage courant est un concept concernant la fois la compilation et lexcution. La plupart des vrifications de nom de variable se font la compilation, mais les vrifications lexcution se font lorsque des rfrences symboliques sont drfrences et quand de nouveaux bouts de code sont analyss avec eval. En particulier, quand vous appliquez eval une chane, Perl sait dans quel paquetage eval a t invoqu et propage ce paquetage vers lintrieur en valuant la chane. (Bien sr, vous pouvez toujours passer un autre paquetage lintrieur de la chane eval, puisquune chane eval compte pour un bloc, tout comme un fichier charg avec un do, un require, ou un use.) Dun autre ct, si eval veut dterminer dans quel paquetage il se trouve, le symbole spcial __PACKAGE__ contient le nom du paquetage courant. Puisque vous pouvez le traiter comme une chane, vous pourriez lutiliser dans une rfrence symbolique pour accder une variable de paquetage. Mais si vous faites cela, il y a des chances que vous ayez plutt intrt dclarer la variable avec our, de sorte quon puisse y accder comme si ctait une variable lexicale.

Tables de symboles
Les lments contenus dans un paquetage sont dans leur ensemble appels table de symboles. Les tables de symboles sont ranges dans un hachage dont le nom est le mme que celui du paquetage, avec un double deux-points ajout la fin. Ainsi le nom de la table de symboles principale, main, est %main::. Puisque main se trouve aussi tre le paquetage par dfaut, Perl fournit %::comme abbrviation pour %main::. De mme, la table de symboles du paquetage Rouge::Bleu est appel %Rouge::Bleu::. Il se trouve que la table de symboles main contient toutes les autres tables de symboles de haut niveau, elle-mme incluse, donc %Rouge::Bleu:: est aussi %main::Rouge::Bleu::. Quand nous disons que la table de symboles contient une autre table de symboles, nous voulons dire quelle contient une rfrence une autre table de symboles. Puisque main est le paquetage de plus haut niveau, il contient une rfrence lui-mme, ainsi %main:: est pareil que %main::main::, et %main::main::main::, et ainsi de suite, ad infinitum. Il est important de prvoir ce cas spcial si vous crivez du code qui parcourt toutes les tables de symboles.

customer_8566

270

Chapitre 10 Paquetages

lintrieur du hachage dune table de symboles, chaque couple clef/valeur fait correspondre un nom de variable sa valeur. Les clefs sont les identificateurs de symbole et les valeurs les typeglobs correspondants. Donc quand vous utilisez la notation typeglob *NOM, vous accdez en ralit une valeur dans le hachage qui contient la table de symboles du paquetage courant. En fait, les instructions suivantes ont (quasiment) le mme effet :
*sym = *main::variable; *sym = $main::{"variable"};

La premire est plus efficace car on accde la table de symboles main au moment de la compilation. Elle crera aussi un nouveau typeglob de ce nom sil nen existait pas prcdemment, alors que la deuxime version ne le fera pas. Puisquun paquetage est un hachage, vous pouvez rechercher les clefs du paquetage et rcuprer toutes les variables du paquetage. Puisque les valeurs du hachage sont des typeglobs, vous pouvez les drfrencer de diverses faons. Essayez ceci :
foreach $nomsym (sort keys %main::) { local *sym = $main::{$nomsym}; print "\$$nomsym est dfini\n" if defined $sym; print "\@$nomsym is non nul\n" if @sym; print "\%$nomsym is non nul\n" if %sym; }

Puisque tous les paquetages sont accessibles (directement ou indirectement) par le paquetage main, vous pouvez crire du code Perl pour visiter chaque variable de paquetage de votre programme. Cest prcisment ce que fait le dbogueur Perl lorsque vous lui demandez dafficher toutes vos variables avec la commande V Notez que si vous faites . cela, vous ne verrez pas les variables dclares avec my, puisquelles sont indpendantes des paquetages, bien que vous verrez les variables dclares avec our. Voir le chapitre 20, Le dbogueur Perl. Prcdemment nous avons dit que seuls les identificateurs taient rangs dans des paquetages autres que main. Ctait un tout petit mensonge : vous pouvez utiliser la chane que vous voulez comme clef dans le hachage de la table de symboles mais a ne serait pas du Perl valide si vous essayiez dutiliser un non-identificateur directement :
$!@#$% ${!@#$%} = 0; = 1; # FAUX, erreur de syntaxe. # Ok, mais non qualifi. # On peut qualifier dans la chane # Ok, imprime 2!

${main::!@#$%} = 2; print ${ $main::{!@#$%} } *dick = *richard;

Les typeglobs servent essentiellement dalias : rend les variables, fonctions, formats, et handles de fichiers et rpertoires accessibles par lidentificateur richard galement accessibles par lidentificateur dick. Si vous ne souhaitez affecter un alias qu une seule variable ou fonction, affectez plutt la rfrence :
*dick = \$richard;

Ce qui fait que $richard et $dick sont littralement la mme variable, mais que @richard et @dick restent des tableaux diffrents. Rus, non ?

customer_8566

Tables de symboles

271

Cest ainsi que fonctionne le paquetage Exporter lorsque lon importe des variables dun paquetage vers un autre. Par exemple :
*UnPack::dick = \&AutrePack::richard;

importe la fonction &richard du paquetage AutrePack dans le paquetage UnPack, le rendant disponible comme fonction &dick. (Le module Exporter sera dcrit dans le prochain chapitre.) Si vous prcdez laffectation avec un local, lalias ne durera que le temps de la porte dynamique courante. Ce mcanisme peut tre utilis pour rcuprer une rfrence partir dune fonction, rendant le rfrent disponible avec le type de donnes appropri :
*unites = renseigner() ; print $unites{kg}; # Affecter \%nouveau_hachage au typeglob # Affiche 70; pas ncessaire de drfrencer!

sub renseigner { my %nouveau_hachage = (km => 10, kg => 70); return \%nouveau_hachage; }

De mme, vous pouvez passer une rfrence une fonction et lutiliser sans la drfrencer :
%unites = (kilometres => 6, kilos => 11); faireleplein( \%unites ); # Passer une rfrence print $unites{litres}; # Affiche 4 sub faireleplein { local *hashsym = shift; $hashsym{litres} = 4; }

# Affecter \%unites au typeglob # Modifie %unites; pas ncessaire # de drfrencer !

Ce sont des moyens astucieux de manipuler des rfrences quand vous ne voulez pas devoir les drfrencer explicitement. Notez que les deux techniques ne fonctionnent quavec des variables de paquetage. Elles ne marcheraient pas si on avait dclar %unites avec my. Les tables de symboles sutilisent aussi pour crer des scalaires constants :
*PI = \3.14159265358979;

Il vous est maintenant impossible daltrer $PI, ce qui probablement une bonne chose, somme toute. Ceci nest pas pareil quune fonction constante, qui est optimise la compilation. Une fonction constante est une fonction dont le prototype indique quelle ne prend pas de paramtres et quelle retourne une expression constante ; voir pour plus de dtails la section Substitution en ligne de fonctions constantes, chapitre 6, Sous-programmes. Le pragma use constant est un raccourci commode :
use constant PI => 3.14159;

Sous le capot, ceci utilise la case fonction de *PI, plutt que la case scalaire utilise ci-dessus. Lexpression suivante, plus compacte (mais moins lisible), est quivalente :
*PI = sub () { 3.14159 };

customer_8566

272

Chapitre 10 Paquetages

En tout cas cest un idiome pratique connatre. Affecter un sub {} un typeglob permet de donner un nom une fonction anonyme lors de lexcution. Affecter une rfrence un typeglob un autre typeglob (*sym = \*oldvar) revient affecter the typeglob en entier, car Perl drfrence automatiquement la rfrence au typeglob votre place. Lorsque vous affectez simplement une chane une typeglob, vous obtenez le typeglob entier nomm par cette chane, car Perl va chercher la chane dans la table de symboles courante. Les instructions suivantes sont toutes quivalentes entre elles, bien que les deux premires sont calcules la compilation, alors que les deux dernires le sont lexcution :
*sym *sym *sym *sym = *anciennevar; = \*anciennevar; # drfrence auto = \*{"anciennevar"}; # recherche explicite dans la table de symboles = "anciennevar"; # recherche implicite dans la table de symboles

Lorsque vous faites lune des affectations suivantes, vous ne faites que remplacer lune des rfrences lintrieur du typeglob :
*sym *sym *sym *sym = = = = \$frodon; \@sam; \%merry; \&pippin;

Dun autre point de vue, le typeglob lui-mme peut tre considr comme une espce de hachage, incluant des entres pour les diffrents types de variables. Dans ce cas, les clefs sont fixes, puisquun typeglob contient exactement un scalaire, un tableau, un hachage, et ainsi de suite. Mais vous pouvez extraire les rfrences individuelles, comme ceci :
*pkg::sym{SCALAR} *pkg::sym{ARRAY} *pkg::sym{HASH} *pkg::sym{CODE} *pkg::sym{GLOB} *pkg::sym{IO} *pkg::sym{NAME} *pkg::sym{PACKAGE} # # # # # # # # pareil que \$pkg::sym pareil que \@pkg::sym pareil que \%pkg::sym pareil que \&pkg::sym pareil que \*pkg::sym handle de fichier/rp interne, pas dquivalent direct "sym" (pas une rfrence) "pkg" (pas une rfrence)

Vous pouvez dire *foo{PACKAGE} et *foo{NAME} pour dterminer de quel nom et et de quel paquetage provient lentre *foo dune table de symboles. Ceci peut tre utile dans une fonction laquelle des typeglobs sont passs en paramtres :
sub identifier_typeglob { my $glob = shift; print Vous mavez donn , *{$glob}{PACKAGE}, ::, *{$glob}{NAME}, "\n" } identifier_typeglob(*foo); identifier_typeglob(*bar::glarch);

Ceci affiche :
Vous mavez donn main::foo Vous mavez donn bar::glarch

customer_8566

Autochargement

273

La notation *foo{TRUC} peut tre utilise pour obtenir des rfrences aux lments individuels de *foo. Voir pour plus de dtails la section Rfrences de table de symboles, chapitre 8. Cette syntaxe est principalement utilise pour accder au handle de fichier ou de rpertoire interne, car les autres rfrences internes sont dj accessibles dautres faons. (Lancien *foo{FILEHANDLE} reste support et signifie *foo{IO}, mais ne laissez pas son nom vous faire croire quil peut distinguer entre des handles de fichier et de rpertoire.) Nous avons pens gnraliser cela parce que quelque part, cest joli. Quelque part. Vous navez probablement pas vous souvenir de tout cela sauf si vous avez lintention dcrire un autre dbogueur de Perl.

Autochargement
Normalement, vous ne pouvez pas appeler une fonction non dfinie. Cependant, sil y a une fonction nomme AUTOLOAD dans le paquetage de la fonction non dfinie (ou dans le cas dune mthode dobjet, dans le paquetage de lune quelconque des classes de base de lobjet), alors la fonction AUTOLOAD est appele avec les mmes paramtres qui seraient passs la fonction dorigine. Vous pouvez dfinir la fonction AUTOLOAD pour quelle retourne des valeurs exactement comme une fonction normale, ou vous pouvez dfinir la fonction qui nexistait pas et ensuite lappeler comme si elle avait exist tout du long. Le nom pleinement qualifi de la fonction dorigine apparat magiquement dans la variable globale au paquetage $AUTOLOAD, dans le mme paquetage que la fonction AUTOLOAD. Voici un exemple simple qui vous avertit gentiment lors des appels de fonctions non dfinies, au lieu darrter le programme.
sub AUTOLOAD { our $AUTOLOAD; warn "la tentative dappeler $AUTOLOAD a chou.\n"; } blarg(10); # notre $AUTOLOAD aura la valeur to main::blarg print "Encore vivant!\n"

Ou vous pouvez retourner une valeur pour le compte de la fonction non dfinie :
sub AUTOLOAD { our $AUTOLOAD; return "Je vois $AUTOLOAD(@_)\n"; } print blarg(20); # affiche: Je vois main::blarg(20)

Votre fonction AUTOLOAD pourrait charger une dfinition de la fonction non dfinie en utilisant eval ou require, ou utiliser lastuce daffectation au glob discute prcdemment, puis excuter cette fonction en utilisant une forme spciale du goto qui peut effacer le stack frame de la fonction sans laisser de trace. Ici nous dfinissons la fonction en affectant une fermeture au glob :
sub AUTOLOAD { my $nom = our $AUTOLOAD;

customer_8566

274

Chapitre 10 Paquetages
*$AUTOLOAD = sub { print "Je vois $nom(@_)\n" }; goto &$AUTOLOAD; # Redmarrer la nouvelle fonction

} blarg(30); glarb(40); blarg(50);

# affiche : je vois main::blarg(30) # affiche : je vois main::glarb(40) # affiche : je vois main::blarg(50)

Le module standard AutoSplit est utilis par les crateurs de modules pour les aider diviser leurs modules en plusieurs fichiers (avec des noms de fichier se terminant avec .al), chacun contenant une fonction. Les fichiers sont placs dans le rpertoire auto/ de la bibliothque Perl de votre systme, aprs quoi les fichiers peuvent tre autochargs par le module standard AutoLoader. Une approche similaire est utilise par le module SelfLoader, mis part quil autocharge des fonctions partir de la zone DATA du fichier lui-mme, ce qui est moins efficace certains gards, et plus efficace dautres. Lautochargement de fonctions Perl par AutoLoader et SelfLoader est analoque au chargement dynamique de fonctions C compiles par DynaLoader, mais lautochargement est fait avec la granularit dun appel de fonction, alors que le chargement dynamique est fait avec la granularit dun module entier, et liera en gnral un grand nombre de fonction C ou C++ la fois. (Notez que beaucoup de programmeurs Perl se dbrouillent trs bien sans les modules AutoSplit, AutoLoader, SelfLoader, or DynaLoader. Il faut juste que vous sachiez quils sont l, au cas o vous ne pourriez pas vous dbrouiller sans eux.) On peut samuser avec des fonctions AUTOLOAD qui servent demballage pour dautres interfaces. Par exemple, faisons semblant quune fonction qui nest pas dfinie doive juste appeler system avec ses paramtres. Tout ce que vous auriez faire est ceci :
sub AUTOLOAD { my $programme = our $AUTOLOAD; $programme =~ s/.*:://; # enlever le nom du paquetage system($programme, @_); }

(Flicitations, vous venez dimplmenter une forme rudimentaire du module Shell qui vient en standard avec Perl.) Vous pouvez appeler votre autochargeur (sur Unix) ainsi :
date(); who(am, i); ls(-l); echo("Ga bu zo meu...");

En fait, si vous prdclarez les fonctions que vous voulez appeler de cette faon, vous pouvez procder comme si elles taient pr-construites dans le langage et omettre les parenthses lors de lappel :
sub sub sub sub date (;$$); who (;$$$$); ls; echo ($@); # # # # Permettre Permettre Permettre Permettre de de un au zro deux paramtres. zro quatre paramtres. nombre quelconque de paramtres. moins un paramtre.

date; who "am", "i"; ls "-l"; echo "Cest tout pour aujourdhui !";

customer_8566

11

Modules

Le module est lunit fondamentale de rutilisation de Perl. bien le regarder, un module nest quun paquetage dfini dans un fichier de mme nom (avec .pm la fin). Dans ce chapitre, nous allons explorer comment utiliser les modules des autres et crer les siens. Perl inclut en standard un grand nombre de modules, que vous pouvez trouver dans le rpertoire lib de votre distribution Perl. Beaucoup de ces modules sont dcrits au chapitre 32, Modules standards, et au chapitre 31, Modules de pragmas. Tous les modules standard ont aussi une documentation dtaille en ligne, qui peut (scandale !) tre plus jour que ce livre. Essayez la commande perldoc si votre commande man ne fonctionne pas. Le Comprehensive Perl Archive Network (CPAN) contient un dpt de modules aliment par la communaut Perl mondiale, et est prsent au chapitre 22, CPAN. Voir aussi http://www.cpan.org.

Utilisation des modules


Il y a deux sortes de modules : traditionnel et orient objet. Les modules traditionnels dfinissent des fonctions et des variables destines tre importes et utilises par un programme qui y fait appel. Les modules orients objet fonctionnent comme des dfinitions de classe auxquelles on accde par des appels de mthodes, dcrites au chapitre 12, Objets. Certains modules font les deux. Les modules Perl sont habituellement inclus dans votre programme en crivant :
use MODULE LISTE;

ou simplement :
use MODULE;

MODULE doit tre un identificateur qui nomme le paquetage et le fichier du module. (Les descriptions de syntaxe ne sont donnes ici qu titre indicatif, car la syntaxe complte de linstruction use est dtaille au chapitre 29, Fonctions.)

customer_8566

276

Chapitre 11 Modules

Linstruction use prcharge MODULE au moment de la compilation, puis importe les symboles que vous avez demands pour quils soient disponibles pour le reste de la compilation. Si vous ne fournissez pas une LISTE des symboles que vous voulez, les symboles nomms dans le tableau @EXPORT interne au module sont utiliss en supposant que vous utilisez le module Exporter, dcrit plus loin dans ce chapitre sous Espace priv de module et Exporter . (Si vous fournissez une LISTE, tous vos symboles doivent tre mentionns, soit dans le tableau @EXPORT, soit dans le tableau @EXPORT_OK, faute de quoi une erreur en rsultera.) Puisque les modules utilisent Exporter pour importer des symboles dans le paquetage courant, vous pouvez utiliser les symboles dun module sans les qualifier avec le nom du paquetage :
use Fred; pierrafeu(); # Si Fred.pm contient @EXPORT = qw(pierrafeu) # ...ceci appelle Fred::pierrafeu().

Tous les fichiers de module Perl ont lextension .pm. Ceci (ainsi que les doubles apostrophes) est pris en compte par use ainsi que par require afin que vous nayez pas crire "MODULE.pm". Cette convention permet de diffrencier les nouveaux modules des bibliothques .pl et .ph utilises dans danciennes versions de Perl. Elle dfinit aussi MODULE comme nom officiel de module, ce qui aide lanalyseur dans certaines situations ambigus. Tout double deux-points dans le nom de module est traduit comme le sparateur de rpertoires de votre systme, de sorte que si votre module a pour nom Rouge::Bleu::Vert, Perl pourrait le chercher sous Rouge/Bleu/Vert.pm. Perl ira chercher vos modules dans tous les rpertoires lists dans le tableau @INC. Comme use charge les modules au moment de la compilation, toutes modifications au tableau @INC doivent aussi survenir au moment de la compilation. Vous pouvez faire cela avec le pragma lib, dcrit au chapitre 31 ou avec un bloc BEGIN. Une fois quun module est inclus, un couple clef/valeur sera ajout au hachage %INC. La clef sera le nom de fichier du module (Rouge/Bleu/Vert.pm dans notre exemple) et la valeur sera le chemin complet, qui pourrait tre quelque chose comme C:/perl/site/lib/Rouge/Bleu/Vert.pm pour un fichier convenablement install sur un systme Windows. Les noms de module doivent commencer avec une lettre majuscule, sauf sils fonctionnent comme pragmas. Les pragmas sont essentiellement des directives de compilation (des conseils pour le compilateur), donc nous rservons les noms de pragma en minuscules pour un usage ultrieur. Lorsque vous utilisez un module avec use, tout le code du module est excut, tout comme il le serait avec un require ordinaire. Sil vous est gal que le module soit pris en compte la compilation ou lexcution, vous pouvez juste dire :
require MODULE;

Cependant, en gnral on prfre use plutt que require, car il recherche les modules la compilation, donc vous dcouvrez les erreurs ventuelles plus tt. Ces deux instructions font presque la mme chose :
require MODULE; require "MODULE.pm";

Elles diffrent nanmoins de deux faons. Dans la premire instruction, require traduit

customer_8566

Cration de modules

277

tout double deux-points en sparateur de rpertoire de votre systme, tout comme le fait use. La deuxime instruction ne fait pas de traduction, vous obligeant spcifier explicitement le chemin de votre module, ce qui est moins portable. Lautre diffrence est que le premier require indique au compilateur que les expressions utilisant la notation objet indirecte avec MODULE (comme $ob = purgeMODULE) sont des appels de mthode, pas des appels de fonction. (Si, a peut rellement faire une diffrence, sil y a une dfinition purge dans votre module qui entre en conf lit avec une autre.) Comme la dclaration use et la dclaration apparente no impliquent un bloc BEGIN, le compilateur charge le module (et excute son ventuel code dinitialisation) ds quil rencontre cette dclaration, avant de compiler le reste du fichier. Cest ainsi que les pragmas peuvent modifier le comportement du compilateur, et que les modules peuvent dclarer des fonctions qui sont par la suite visibles comme oprateurs de liste pour le reste de la compilation. Ceci ne marchera pas si vous utilisez un require la place dun use. La seule raison dutiliser un require est davoir deux modules dont chacun ncessite une fonction de lautre. (Et nous ne sommes pas srs que ce soit une bonne raison.) Les modules Perl chargent toujours un fichier .pm, mais ce fichier peut son tour charger des fichiers associs, comme des bibliothques C ou C++ lies dynamiquement, ou des dfinitions de fonction Perl autocharges. Dans ce cas, les complications supplmentaires seront entirement invisibles pour lutilisateur du module. Cest la responsabilit du fichier .pm de charger (ou de sarranger pour autocharger) toute fonctionnalit supplmentaire. Il se trouve que le module POSIX fait du chargement dynamique et de lautochargement, mais lutilisateur peut simplement dire :
use POSIX;

pour avoir accs toutes les fonctions et variables exportes.

Cration de modules
Prcdemment, nous avons dit quun module a deux faons de mettre son interface la disposition de votre programme : en exportant des symboles ou en permettant des appels de fonction. Nous vous montrerons un exemple de la premire technique ici ; la deuxime technique est utilise pour les modules orients objet, et est dcrite dans le prochain chapitre. (Les modules orients objet ne devraient rien exporter, car les mthodes objet ont pour principe que Perl les trouve automatiquement votre place en se basant sur le type de lobjet.) Pour construire un module appel Bestiaire, crez un fichier appel Bestiaire.pm qui ressemble ceci :
package require our our our our Bestiaire; Exporter; = = = = qw(Exporter); qw(dromadaire); qw($poids); 1.00;

@ISA @EXPORT @EXPORT_OK $VERSION

# Symboles exporter par dfaut # Symboles exporter la demande # Numro de version

### Mettez vos variables et vos fonctions ici

customer_8566

278
sub dromadaire { print "Chameau une seule bosse" } $poids = 1024; 1;

Chapitre 11 Modules

Maintenant un programme peut dire use Bestiaire pour pouvoir accder la fonction dromadaire (mais pas la variable $poids), et use Bestiaire qw(dromadaire $poids) pour accder la fois la fonction et la variable. Vous pouvez galement crer des modules qui chargent dynamiquement du code crit en C. Voir le chapitre 21, Mcanismes internes et accs externes, pour plus de dtails.

Espace priv de module et Exporter


Perl ne patrouille pas automatiquement le long de frontires entre le priv et le public dans ses modules ontrairement des langages comme C++, Java et Ada, Perl nest pas obsd par le droit la vie prive. Un module Perl prfrerait que vous restiez hors de son salon parce que vous ny avez pas t invit, pas parce quil a un fusil. Le module et son utilisateur ont un contrat, dont une partie se base sur la loi coutumire, et dont lautre est crite. Une partie du contrat de loi coutumire est quun module doit sabstenir de modifier tout espace de noms quon ne lui a pas demand de modifier. Le contrat crit du module (cest--dire la documentation) peut prendre dautres dispositions. Mais vous savez sans doute, aprs avoir lu le contrat, que quand vous dites use RedefinirLeMonde vous redfinissez le monde, et vous tes prt en risquer les consquences. La faon la plus commune de redfinir des mondes est dutiliser le module Exporter. Comme nous le verrons plus loin dans ce chapitre, vous pouvez mme redfinir des fonctions Perl de base avec ce module. Lorsque vous faites appel un module avec use, le module met habituellement certaines fonctions et variables la disposition de votre programme, ou plus prcisment du paquetage courant de votre programme. Cet acte dexportation de symboles du module (et donc dimportation dans votre programme) est parfois appel pollution de votre espace de noms. La plupart des modules utilisent Exporter pour faire cela. Cest pourquoi la plupart des modules disent quelque chose comme ceci vers le dbut :
require Exporter; our @ISA = ("Exporter");

Ces deux lignes font hriter au module de la classe Exporter. Lhritage est dcrit au prochain chapitre, mais tout ce que vous avez besoin de savoir cest que notre module Bestiaire peut maintenant exporter des symboles dans dautres paquetages avec des lignes comme celle-ci :
our @EXPORT = qw($chameau %loup belier); # Exporter par dfaut our @EXPORT_OK = qw(leopard @lama $emeu); # Exporter la demande our %EXPORT_TAGS = ( # Exporter en groupe camelides => [qw($chameau @lama)], bestiaux => [qw(belier $chameau %loup)], );

Du point de vue du module qui exporte, le tableau @EXPORT contient les noms de varia-

customer_8566

Cration de modules

279

bles et de fonctions exporter par dfaut : ce quobtient votre programme lorsquil dit use Bestiaire. Les variables et les fonctions dans @EXPORT_OK ne sont exportes que lorsque le programme en fait explicitement la demande dans linstruction use. Enfin, les couples clef/valeur dans %EXPORT_TAGS permettent au programme dinclure des groupes de symboles spcifiques, lists dans @EXPORT et @EXPORT_OK. Du point de vue du module qui importe, linstruction use spcifie la liste des symboles importer, un groupe nomm %EXPORT_TAGS, un motif de symboles, ou rien du tout, auquel cas les symboles dans @EXPORT seront imports du module dans votre programme. Vous pouvez inclure lune quelconque de ces instructions pour importer des symboles du module Bestiaire :
use Bestiaire; # Importer les symboles de @EXPORT use Bestiaire (); # Ne rien importer use Bestiaire qw(belier @lama); # Importer la fonction belier et le # tableau @lama use Bestiaire qw(:camelides); # Importer $chameau et @lama use Bestiaire qw(:DEFAULT); # Importer les symboles de @EXPORT use Bestiaire qw(/am/); # Importer $chameau et @lama use Bestiaire qw(/^\$/); # Importer tous les scalaires use Bestiaire qw(:bestiaux !belier); # Importer bestiaux, mais exclure belier use Bestiaire qw(:bestiaux !:camelides); # Importer bestiaux, mais pas camelides

Omettre un symbole des listes dexportation (ou le supprimer explicitement de la liste dimport avec le point dexclamation) ne le rend pas inaccessible pour le programme qui utilise le module. Le programme pourra toujours accder au contenu du paquetage du module en le qualifiant avec le nom du paquetage, comme par exemple %Bestiaire::gecko. (Comme les variables lexicales nappartiennent pas au paquetage, lespace priv est possible : voir Mthodes prives au chapitre suivant.) Vous pouvez dire BEGIN { $Exporter::Verbose=1 } pour voir comment sont gres les spcifications et pour voir ce qui est rellement import dans votre paquetage. Exporter est lui-mme un module Perl, et si cela vous intresse vous pouvez voir les astuces typeglob qui sont utilises pour exporter des symboles dun paquetage un autre. lintrieur du module Exporter, la fonction essentielle, appele import, cre les alias ncessaires pour quun symbole dun paquetage soit visible dans un autre paquetage. En fait, linstruction use BestiaireLISTE est prcisment quivalente :
BEGIN { require Bestiaire; import Bestiaire LISTE; }

Cela veut dire que vos modules ne sont pas obligs dutiliser Exporter. Un module peut faire ce qui lui plat, puisque use ne fait quappeler la mthode import du module, et vous pouvez dfinir cette mthode pour quelle fasse ce que vous voulez.

customer_8566

280

Chapitre 11 Modules

Exporter sans utiliser la mthode import de Exporter


Le module Exporter dfinit une mthode appele export_to_level pour les situations o vous ne pouvez pas directement appeler la mthode import de Exporter. La mthode export_to_level est invoque comme ceci : MODULE->export_to_level($ou_exporter, @quoi_exporter); Lentier $ou_exporter indique quelle hauteur dans la pile dappel exporter vos symboles, et le tableau $quoi_exporter liste les symboles exporter (habituellement @_). Par exemple, supposons que notre Bestiaire contienne sa propre fonction import :
package Bestiaire; @ISA = qw(Exporter); @EXPORT_OK = qw ($zoo); sub import { $Bestiaire::zoo = "mnagerie"; }

La prsence de cette fonction import empche dhriter de la fonction import de Exporter. Si vous vouliez quaprs avoir affect $Bestiaire::zoo, la fonction import de Bestiaire se comporte exactement comme la fonction import de Exporter, vous la dfiniriez de la faon suivante :
sub import { $Bestiaire::zoo = "mnagerie"; Bestiaire->export_to_level(1, @_); }

Ceci exporte des symboles vers le paquetage situ un niveau au-dessus du paquetage courant, cest--dire vers tout programme ou module qui utilise Bestiaire.

Vrification de version
Si votre module dfinit une variable $VERSION, un programme qui utilise votre module peut sassurer que le module est suffisamment rcent. Par exemple :
use Bestiaire 3.14; # Le Bestiaire doit tre de version 3.14 ou plus use Bestiaire v1.0.4; # Le Bestiaire doit tre de version 1.0.4 ou plus

Ces instructions sont converties en appels Bestiaire->require_version, dont hrite ensuite votre module.

Gestion de symboles inconnus


Dans certaines situations, vous voudrez peut-tre empcher lexportation de certains symboles. Typiquement, cest le cas de certains modules qui ont des fonctions ou des constantes qui nont pas de sens sur certains systmes. Vous pouvez empcher Exporter dexporter ces symboles en les plaant dans le tableau @EXPORT_FAIL. Si un programme tente dimporter lun de ces symboles, Exporter permet au module de grer la situation avant de produire une erreur. Il le fait en appelant une mthode export_fail avec une liste des symboles qui ont chou, que vous pouvez dfinir ainsi (en supposant que votre module utilise le module Carp) :

customer_8566

Supplanter des fonctions internes


sub export_fail { my $class = shift; carp "Dsol, ces symboles ne sont pas disponibles : @_"; return @_; }

281

Exporter fournit une mthode export_fail par dfaut, qui retourne simplement la liste inchange et fait chouer le use en levant une exception pour chaque symbole. Si export_fail retourne une liste vide, aucune erreur nest enregistre et tous les symboles demands sont exports.

Fonctions de gestion des tiquettes


Comme les symboles lists dans %EXPORT_TAGS doivent galement apparatre, soit dans @EXPORT, soit dans @EXPORT_OK, Exporter fournit deux fonctions qui vous permettent dajouter ces ensembles de symboles tiquets.
%EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]); Exporter::export_tags(foo); Exporter::export_ok_tags(bar); # ajouter aa, bb et cc @EXPORT # ajouter aa, cc et dd @EXPORT_OK

Cest une erreur de spcifier des noms qui ne sont pas des tiquettes.

Supplanter des fonctions internes


De nombreuses fonctions internes peuvent tre supplantes, bien que (comme pour faire des trous dans vos murs) vous ne devriez faire cela que rarement et pour de bonnes raisons. Typiquement, ce serait fait par un paquetage qui tente dmuler des fonctions internes manquantes sur un systme autre quUnix. (Ne confondez pas supplanter avec surcharger, qui ajoute des significations orientes objet supplmentaires aux oprateurs internes, mais ne supplante pas grand chose. Le module overload dans le chapitre 13, Surcharge, donne plus de dtails sur ce sujet.) On ne peut supplanter quen important le nom dun module ; la prdclaration ordinaire ne suffit pas. Pour tre parfaitement francs, cest laffectation dune rfrence de code un typeglob qui permet Perl de supplanter, comme dans *open = \&myopen. De plus, laffectation doit survenir dans un autre paquetage ; ceci rend intentionnellement difficile de supplanter accidentellement par alias de typeglob. Malgr tout, si vous voulez vraiment supplanter vous-mme, ne dsesprez pas, car le pragma subs vout permet de prdclarer des fonctions avec la syntaxe dimportation, et ces noms supplantent alors ceux qui existent en interne :
use subs qw(chdir chroot chmod chown); chdir $quelque_part sub chdir { ... }

En gnral, les modules ne doivent pas exporter des noms internes comme open ou chdir comme partie de leur liste @EXPORT par dfaut, puisque ces noms pourraient se glisser dans lespace de noms de quelquun dautre et en changer le contenu de faon inattendue. Si au lieu de cela le module inclut le nom dans la liste @EXPORT_OK, les importateurs seront obligs de demander explicitement que le nom interne soit supplant, vitant ainsi les surprises.

customer_8566

282

Chapitre 11 Modules

La version dorigine des fonctions internes est toujours accessible via le pseudo-paquetage CORE. En consquence, CORE::chdir sera toujours la version compile dorigine dans Perl, mme si le mot-clef chdir a t supplant. Enfin, presque toujours. Le mcanisme dcrit ci-dessus pour supplanter les fonctions internes est restreint, trs dlibrment, au paquetage qui fait la demande dimportation. Mais il existe un mcanisme plus radical que vous pouvez utiliser lorsque vous souhaitez supplanter une fonction interne partout, sans prendre en compte les frontires despaces de noms. Ceci est accompli en dfinissant la fonction dans le pseudo-paquetage CORE::GLOBAL. Voyez ci-dessous un exemple qui supplante loprateur glob avec quelque chose qui comprend les expressions rationnelles. (Notez que cet exemple nimplmente pas tout ce qui est ncessaire pour supplanter proprement le glob interne de Perl, qui se comporte diffremment selon quil apparat dans un contexte scalaire ou un contexte de liste. En vrit, de nombreuses fonctions internes de Perl ont de tels comportements sensibles au contexte, et tout fonction visant les correctement supplanter une fonction interne doit grer adquatement ces comportements. Pour voir un exemple compltement fonctionnel o glob est supplant, tudiez le module File::Glob inclus avec Perl.) En tout cas, voici la version anti-sociale :
*CORE::GLOBAL::glob = sub { my $motif = shift; my @trouve; local *D; if (opendir D, .) { @trouve = grep /$motif/, readdir D; closedir D; } return @trouve; } package Quelconque; print <^[a-z_]+\.pm\$>; # montrer tous les pragmas dans le rpertoire courant

En supplantant glob globalement, ceci impose un nouveau (et subversif) comportement pour loprateur glob dans tous les espaces de noms, sans la connaissance ou la coopration des modules popritaires de ces espaces de noms. Bien sr, sil faut faire cela, il faut le faire avec la plus extrme prudence. Et probablement il ne faut pas le faire. Nous supplantons avec le principe suivant : cest sympa dtre important, mais cest plus important dtre sympa.

customer_8566

12
Bref rappel de vocabulaire orient objet

Objets

Pour commencer, vous devez comprendre les paquetages et les modules ; voir le chapitre 10, Paquetages, et le chapitre 11, Modules. Vous devez aussi connatre les rfrences et les structures de donnes ; voir le chapitre 8, Rfrences, et le chapitre 9, Structures de donnes. Comme il est utile de sy connatre un peu en programmation oriente objet, nous vous donnerons un petit cours de vocabulaire orient objet dans la section suivante.

Un objet est une structure de donnes munie dune collection de comportements. Nous dirons parfois quun objet agit directement sur la base de comportements, allant parfois jusqu lanthropomorphisme. Par exemple, nous dirons quun rectangle sait comment safficher lcran ou quil sait comment calculer sa propre surface. Un objet exhibe des comportements en tant une instance dune classe. La classe dfinit des mthodes : des comportements qui sappliquent la classe et ses instances. Lorsquil faut faire la distinction, nous appelons mthode dinstance une mthode qui ne sapplique qu un objet donn et mthode de classe une mthode qui sapplique la classe dans son entier. Mais ce nest quune convention : pour Perl, une mthode nest quune mthode qui ne se distingue que par le type de son premier argument. Vous pouvez considrer quune mthode dinstance est une action excute par un objet donn, comme laction de safficher, de se copier ou de modifier une ou plusieurs de ses proprits ( affecter Anduril au nom de cette pe ). Les mthodes de classe peuvent excuter des oprations sur un ensemble dobjets ( afficher toutes les pes ) ou fournir dautres oprations qui ne dpendent pas dun objet particulier ( partir de maintenant, chaque fois quune nouvelle pe est forge, enregistrer dans cette base de donnes le nom de son propritaire ). Les mthodes qui produisent des instances (ou objets) dune classe sont appeles constructeurs ( crer une pe incruste de pierres prcieuses et avec une inscription secrte ). Celles-ci sont en gnral des mthodes de classe ( fais-moi une nouvelle pe ), mais elles peuvent aussi tre des mthodes dinstance ( fais-moi une copie exacte de cette pe-ci ).

customer_8566

284

Chapitre 12 Objets

Une classe peut hriter des mthodes de classes parentes, appeles aussi classes de base ou surclasses. Dans ce cas, on lappelle classe drive ou sous-classe. (Brouillant un peu les cartes, certains livres entendent par classe de base la surclasse racine , mais ce nest pas ce que nous voulons dire.) Lorsque vous invoquez une mthode dont la dfinition ne se trouve pas dans la classe, Perl consulte automatiquement les classes parentes pour chercher une dfinition. Par exemple, une classe pe pourrait hriter sa mthode attaquer dune classe gnrique arme destoc et de taille . Les classes parentes peuvent elles-mmes avoir des classes parentes, et Perl examinera galement ces classes si besoin est. La classe arme destoc et de taille peut son tour hriter la mthode attaquer dune classe encore plus gnrique arme . Lorsque la mthode attaquer est invoque sur un objet, le comportement rsultant peut varier, selon que lobjet est une pe ou une f lche. Il se peut quil ny ait aucune diffrence, ce qui serait le cas si les pes et les f lches hritaient leur comportement dattaque de la classe arme gnrique. Mais sil y avait une diffrence de comportement, le mcanisme dacheminement de mthode slectionnerait toujours la mthode attaquer la plus approprie pour le type dobjet donn. Cette proprit fort utile de slection du comportement le plus appropri pour un type donn dobjet sappelle le polymorphisme. Cest une faon importante de ne se soucier de rien. Vous devez vous soucier des entrailles de vos objets lorsque vous implmentez une classe, mais lorsque vous utilisez une classe (avec use), vous devriez traiter vos objets comme des botes noires . Vous ne voyez pas ce quil y a lintrieur, vous navez pas besoin de savoir comment a marche, et vous interagissez avec la bote sur ses termes : par les mthodes fournies par la classe. Cest comme la tlcommande de votre tlviseur : mme si vous savez ce qui se passe dedans, vous ne devriez pas sans bonne raison trifouiller dans ses entrailles. Perl vous permet de scruter lintrieur dun objet de lextrieur de la classe lorsque vous en avez besoin. Mais de faire ainsi enfreint lencapsulation, le principe qui spare linterface publique (comment un objet doit tre utilis) de limplmentation (comment lobjet fonctionne en ralit). Perl ne fournit pas un dispositif dinterface explicite, mis part le contrat implicite entre le concepteur et lutilisateur. Lun et lautre sont censs tre raisonnables et respectueux : lutilisateur en ne dpendant que de linterface documente, le concepteur en prservant cette interface. Perl ne vous impose pas un style de programmation particulier, et ne partage pas lobsession avec la vie prive dautres langages de programmation oriente objet. Nanmoins Perl a lobsession de la libert, et lune de vos liberts en tant que programmeur Perl est le droit de choisir si vous voulez beaucoup ou peu de vie prive. En fait, Perl permet un espace priv plus restrictif encore que C++. Cest--dire quil ny a rien que Perl vous empche de faire, et en particulier il ne vous empche pas de vous empcher vous-mme, si ce genre de choses vous intresse. Les sections Mthodes prives et Utilisation de fermetures pour objets privs de ce chapitre vous montrent comment vous pouvez augmenter votre dose de discipline. Reconnaissons quil y a beaucoup plus dire sur les objets, et beaucoup de faons den apprendre plus sur la conception oriente objet. Mais ce nest pas notre propos. Continuons donc.

customer_8566

Le systme objet de Perl

285

Le systme objet de Perl


Perl ne fournit pas de syntaxe objet particulire pour dfinir les objets, les classes ou les mthodes. Au lieu de cela, il rutilise des constructions existantes pour implmenter ces trois notions.1 Voici quelques dfinitions simples que vous trouverez peut-tre rassurantes : Un objet nest quune rfrence... enfin, un rfrent. Comme une rfrence permet de reprsenter une collection de donnes avec un seul scalaire, il ne devrait pas tre surprenant quon utilise les rfrences pour tous les objets. Pour tre prcis, un objet nest pas la rfrence elle-mme, mais plutt le rfrent sur lequel pointe la rfrence. Toutefois cette distinction est souvent brouille par les programmeurs Perl, et comme nous trouvons que cest une jolie mtonymie, nous la perptuons ici lorsque cela nous arrange.2 Une classe nest quun paquetage. Un paquetage agit comme une classe en utilisant les fonctions du paquetage pour excuter les mthodes de la classe et en utilisant les variables du paquetage pour contenir les donnes globales de la classe. Souvent, on utilise un module pour contenir une ou plusieurs classes. Une mthode nest quune fonction. Vous dclarez simplement des fonctions dans le paquetage que vous utilisez comme classe ; celles-ci seront ensuite utilises comme mthodes de la classe. Linvocation de mthode, une nouvelle faon dappeler une fonction, ajoute un paramtre supplmentaire : lobjet ou le paquetage utilis pour invoquer la mthode.

Invocation de mthode
Si vous aviez rduire toute la programmation oriente objet une notion essentielle, ce serait labstraction. Cest le fil conducteur de tous ces mots ronf lants quaiment employer les enthousiastes OO, comme le polymorphisme, lhritage et lencapsulation. Nous croyons en ces mots savants, mais nous les traiterons du point de vue pratique de ce que signifie invoquer des mthodes. Les mthodes sont au cur des systmes objet parce quelles fournissent la couche dabstraction ncessaire limplmentation de ces termes savants. Au lieu daccder directement une donne rsidant dans un objet, vous invoquez une mthode dinstance. Au lieu dappeler directement une fonction dans un paquetage, vous invoquez une mthode de classe. En interposant un niveau dindirection entre lutilisation dune classe et son implmentation, le concepteur de programme reste libre de bricoler le fonctionnement interne de la classe, sans grand risque dinvalider des programmes qui lutilisent. Perl permet deux formes syntaxiques diffrentes pour invoquer les mthodes. Lune utilise le style familier que vous avez dj vu ailleurs en Perl, et la seconde est une forme

1. En voil un exemple de rutilisation de logiciel ! 2. Nous prfrons vigueur linguistique rigueur mathmatique. Vous serez daccord ou non.

customer_8566

286

Chapitre 12 Objets

que vous aurez peut-tre dj rencontre dans dautres langages de programmation. Quelle que soit la forme dinvocation de mthode utilise, un paramtre initial supplmentaire est pass la fonction servant de mthode. Si une classe est utilise pour invoquer la mthode, ce paramtre sera le nom de la classe. Si un objet est utilis pour invoquer la mthode, ce paramtre sera la rfrence lobjet. Quel que soit ce paramtre, nous lappellerons invoquant de la mthode. Pour une mthode de classe, linvoquant est le nom dun paquetage. Pour une mthode dinstance, linvoquant est la rfrence qui spcifie un objet. En dautres termes, linvoquant est ce avec quoi la mthode a t invoque. Certains livres OO lappellent lagent ou lacteur de la mthode. Dun point de vue grammatical, linvoquant nest ni le sujet de laction, ni son destinataire. Il est plutt comme un objet indirect, le bnficiaire au nom duquel laction est excute tout comme le mot moi dans la commande Forge-moi une pe ! . Smantiquement vous pouvez voir linvoquant comme ce qui invoque ou ce qui est invoqu, selon ce qui correspond mieux votre appareil mental. Nous nallons pas vous dire comment penser. (Pas sur ce sujet-l, en tout cas.) La plupart des mthodes sont invoques explicitement, mais des mthodes peuvent aussi tre invoques implicitement lorsquelles sont dclenches par un destructeur dobjet, un oprateur surcharg ou une variable lie. Ce ne sont pas proprement parler des appels de fonction ordinaires, mais plutt des invocations de mthode dclenches automatiquement par Perl au nom de lobjet. Les destructeurs sont dcrits plus loin dans ce chapitre, la surcharge est dcrite dans le chapitre 13, Surcharge, et les variables lies sont dcrites dans le chapitre 14, Variables lies. Les mthodes et les fonctions normales diffrent par le moment auquel leur paquetage est rsolu cest--dire, le moment o Perl dcide quel code doit tre excut pour la mthode ou la fonction. Le paquetage dune fonction est rsolu la compilation, avant que le programme ne commence sexcuter.3 Au contraire, le paquetage dune mthode nest rsolu que lorsquelle est effectivement invoque. (Les prototypes sont vrifis la compilation, cest pourquoi les fonctions normales peuvent les utiliser, mais les mthodes ne le peuvent pas.) La raison pour laquelle le paquetage dune mthode ne peut pas tre rsolu plus tt est relativement vidente : le paquetage est dtermin par la classe de linvoquant, et linvoquant nest pas connu tant que la mthode na rellement t invoque. Au cur de lOO est cette simple chane logique : si on connat linvoquant, on connat la classe de linvoquant ; si on connat la classe, on connat lhritage de la classe ; si on connat lhritage de la classe, on connat la fonction appeler. La logique de labstraction a un cot. cause de la rsolution tardive des mthodes, une solution oriente objet en Perl risque de sexcuter plus lentement que la solution nonOO correspondante. Pour certaines des techniques sophistiques dcrites plus loin, elle pourrait tre beaucoup plus lente. Toutefois, la solution de beaucoup de problmes nest
3. Plus prcisment, lappel de fonction est rsolu jusqu un typeglob spcifique, et une rfrence ce typeglob est rentre dans larbre dopcodes compils. Le sens de ce typeglob est ngociable mme au moment de lexcution cest ainsi que AUTOLOAD peut vous autocharger une fonction. Normalement, cependant, le sens du typeglob est aussi rsolu la compilation par la dfinition dune fonction nomme de faon correspondante.

customer_8566

Invocation de mthode

287

pas de travailler plus vite, mais de travailler plus intelligemment. Cest l que brille lOO.

Invocation de mthode avec loprateur f lche


Nous avons indiqu quil existe deux styles dinvocation de mthode. Le premier style se prsente comme ceci : INVOQUANT->METHODE(LISTE) INVOQUANT->METHODE Pour des raisons videntes, ce style est habituellement appel la forme f lche dinvocation. (Ne confondez pas -> avec =>, la f lche deux coups utilise comme virgule de luxe.) Les parenthses sont exiges sil y a des paramtres. Lorsquelle est excute, linvocation commence par trouver la fonction dtermine conjointement par la classe de lINVOQUANT et par le nom de la METHODE, lui passant INVOQUANT comme premier paramtre. Lorsque INVOQUANT est une rfrence, nous disons que METHODE est invoque comme mthode dinstance, et lorsque INVOQUANT est un nom de paquetage, nous disons que METHODE est invoque comme mthode de classe. Il ny a en ralit aucune diffrence entre les deux, mis part que le nom de paquetage est plus clairement associ la classe ellemme quavec les objets de la classe. Vous allez devoir nous faire confiance lorsque nous disons que les objets connaissent leur classe. Nous vous dirons bientt comment associer un objet un nom de classe, mais vous pouvez utiliser les objets sans savoir cela. Par exemple, pour construire un objet avec la mthode de classe invoquer puis invoquer la mthode dinstance dire sur lobjet rsultant, vous pourriez dire ceci :
$mage = Magicien->invoquer("Gandalf"); # mthode de classe $mage->dire("ami"); # mthode dinstance

Les mthodes invoquer et dire sont dfinies par la classe Magicien --- ou par une des classes dont elle hrite. Mais ne vous inquitez pas de cela. Ne vous mlez pas des affaires de Magiciens. Comme loprateur f lche est associatif vers la gauche (voir le chapitre 3, Oprateurs unaires et binaires), vous pouvez mme combiner les deux instructions :
Magicien->invoquer("Gandalf")->dire("ami");

Parfois vous souhaiterez invoquer une mthode sans connatre son nom par avance. Vous pouvez utiliser la forme f lche dinvocation et remplacer le nom de mthode avec une simple variable scalaire :
$methode = "invoquer"; $mage = Magicien->$methode("Gandalf"); # Invoquer Magicien->invoquer $voyager = $compagnon eq "Grispoil" ? "monter" : "marcher"; $mage->$voyager("sept lieues"); # Invoquer $mage->monter ou # $mage->marcher

Bien que vous utilisiez le nom dune mthode pour linvoquer indirectement, cet usage nest pas interdit par use strict refs, car tous les appels de mthode sont en fait recherchs par symbole au moment o ils sont rsolus.

customer_8566

288

Chapitre 12 Objets

Dans notre exemple, nous stockons le nom dune fonction dans $voyager, mais vous pourriez aussi stocker une rfrence de fonction. Ceci contourne lalgorithme de recherche de mthode, mais parfois cest exactement ce que vous voulez faire. Voir la section Mthodes prives et la discussion de la mthode can dans la section UNIVERSAL : la classe anctre ultime. Pour crer une rfrence la mthode spcifique dappel pour une instance spcifique, voir la section Fermetures dans le chapitre 8.

Invocation de mthode avec des objets indirects


Le second style dinvocation de mthode se prsente comme ceci : METHODE INVOQUANT (LISTE) METHODE INVOQUANT LISTE METHODE INVOQUANT Les parenthses autour de LISTE sont optionnelles ; si elles sont omises, la mthode se comporte comme un oprateur de liste. Vous pouvez donc avoir des instructions comme les suivantes, toutes utilisant ce style dappel de mthode :
$mage = invoquer Magicien "Gandalf"; $nemesis = invoquer Balrog demeure => "Moria", arme => "fouet"; deplacer $nemesis "pont"; dire $mage "Tu ne peux pas passer"; briser $baton; # il est plus sr dutiliser : briser $baton ();

La syntaxe doprateur de liste devrait vous tre familire, car cest le mme style quon utilise pour passer des handles de fichiers print ou printf :
print STDERR "au secours !!!\n";

Elle est galement similaire des phrases en franais comme Donner () Gollum le trsor , donc nous lappelons la forme avec objet indirect. Linvoquant est attendu dans la case dobjet indirect. Lorsquil est fait mention de passer quelque chose une fonction interne comme system ou exec dans sa case dobjet indirect , cela veut dire que vous fournissez ce paramtre supplmentaire et dpourvu de virgule au mme endroit que vous le feriez si vous invoquiez une mthode avec la syntaxe dobjet indirect. La forme avec objet indirect vous permet mme de spcifier que lINVOQUANT soit un BLOC valuable comme objet (rfrence) ou comme classe (paquetage). Ce qui vous permet de combiner deux invocations en une instruction ainsi :
dire { invoquer Magicien "Gandalf" } "ami";

Piges syntaxiques avec les objets indirects


Une syntaxe sera souvent plus lisible que lautre. La syntaxe dobjet indirect est moins lourde, mais souffre de plusieurs sortes dambigut syntaxique. La premire est que la partie LISTE dune invocation avec objet indirect est analyse de la mme faon que tout autre oprateur de liste. Ainsi, les parenthses de :
enchanter $epee ($points + 2) * $cout;

sont censes entourer tous les paramtres, quel que soit ce qui suit. Cela quivaut :
($epee->enchanter($points + 2)) * $cout;

customer_8566

Invocation de mthode

289

Cela ne fait probablement pas ce que vous pensez : enchanter nest appele quavec $points + 2, et la valeur de retour de la mthode est ensuite multiplie par $cout. Comme avec dautres oprateurs de liste, vous devez faire attention la prcdence de && et de || par rapport and et or. Par exemple ceci :
appeler $epee $ancien_nom || "Glamdring"; # ne pas utiliser "or" ici !

devient comme prvu :


$epee->appeler($ancien_nom || "Glamdring");

mais ceci :
dire $mage "ami" && entrer(); # il aurait fallu "and" ici !

devient le douteux :
$mage->dire("ami" && entrer());

qui pourrait tre corrig en rcrivant avec une des formes quivalentes :
entrer() if $mage->dire("ami"); $mage->dire("ami") && entrer(); dire $mage "ami" and entrer();

Le deuxime ennui syntaxique de la forme avec objet indirect est que lINVOQUANT ne peut tre quun nom, une variable scalaire non-indice ou un bloc.4 Ds que lanalyseur voit une de ces choses, il a son INVOQUANT, donc il commence chercher sa LISTE. Ainsi ces invocations :
deplacer $groupe->{CHEF}; deplacer $cavaliers[$i]; # probablement faux ! # probablement faux !

sont en fait analyses comme celles-ci :


$groupe->deplacer->{CHEF}; $cavaliers->deplacer([$i]);

au lieu de ce que vous vouliez sans doute :


$groupe->{CHEF}->deplacer; $cavaliers[$i]->deplacer;

Lanalyseur ne regarde quun petit peu vers lavant pour trouver linvoquant dun objet indirect, pas mme aussi loin quil ne regarderait dans le cas dun oprateur unaire. Cette bizarrerie na pas lieu avec la premire forme syntaxique, donc vous souhaiterez peuttre faire de la f lche votre arme de choix. Mme en franais il peut se poser un problme similaire. Pensez linstruction : Envoyez-moi par la poste la lettre pour que je la lise . Si vous analysez cette phrase trop vite, vous finirez par envoyer quelquun, et non pas une lettre, par la poste. Comme Perl, le franais a parfois deux syntaxes diffrentes pour dcrire un agent : Envoyezmoi la lettre et Envoyez la lettre moi . Parfois la forme plus longue est plus claire et plus naturelle, et parfois cest le contraire. Au moins en Perl, vous tes oblig dutiliser des accolades autour dun objet indirect complexe.
4. Les lecteurs attentifs se souviendront que cest prcisment la mme liste ditems syntaxiques qui sont permis aprs les drles de caractres ($, @, % ou *) pour indiquer un drfrencement de variable par exemple, @tableau, @$ref_tableau ou @{$ref_tableau}.

customer_8566

290

Chapitre 12 Objets

Classes paquetage explicite


La dernire ambigut syntaxique du style dinvocation de mthode avec objet indirect est quelle peut ne pas du tout tre analyse comme appel de mthode, parce que le paquetage courant peut contenir une fonction ayant le mme nom que la mthode. Lorsque vous utilisez une mthode de classe avec un nom de paquetage littral comme invoquant, il y a moyen de rsoudre cette ambigut tout en gardant la syntaxe dobjet indirect : explicitez le nom de paquetage en y ajoutant un double deux-points.
$obj = methode CLASSE::; $obj = new CLASSE; # imposer "CLASSE"->methode # pourrait ne pas tre analys comme mthode

Ceci est important car la notation courante : ne se comportera pas toujours correctement si le paquetage courant comporte une fonction nomme new ou CLASSE. Mme si prudemment vous utilisez la forme avec f lche au lieu de la forme avec objet indirect pour invoquer des mthodes, ceci peut, rarement, rester un problme. Au prix dun peu plus de ponctuation, la notation CLASSE:: garantit comment Perl analysera votre invocation de mthode. Dans les exemples suivants, les deux premiers ne sont pas toujours analyss de la mme faon, mais les deux derniers le sont :
$obj = new AnneauElfique; $obj = AnneauElfique->new; $obj = new AnneauElfique::; $obj = AnneauElfique::->new; $obj = new AnneauElfique:: nom => proprietaire => domaine => pierre => # pourrait tre new("AnneauElfique") # ou mme new(AnneauElfique()) # pourrait tre AnneauElfique()->new() # toujours "AnneauElfique"->new() # toujours "AnneauElfique"->new()

Cette notation de paquetage explicite peut tre enjolive avec un peu dalignement :
"Narya", "Gandalf", "feu", "rubis";

Nanmoins, vous vous exclamerez peut-tre Quil est laid ! en voyant ce double deux-points, donc nous vous dirons que vous pouvez presque toujours vous en sortir avec un simple nom de classe, deux conditions. Premirement, quil ny ait pas de fonction avec le mme nom que la classe. (Si vous observez la convention que les noms de fonction comme new commencent avec une lettre minuscule, et que les noms de classe comme AnneauElfique commencent avec une majuscule, ceci ne posera jamais de problme.) Deuximement, que la classe soit charge avec lune des instructions suivantes :
use AnneauElfique; require AnneauElfique;

Chacune de ces dclarations assure que Perl sait que AnneauElfique est un nom de module, ce qui oblige tout nom simple comme new avant le nom de classe AnneauElfique tre interprt comme un appel de mthode, mme sil se trouve que vous avez vousmme dclar une fonction new dans le paquetage courant. On ne rencontre habituellement de problme avec les objets indirects que si lon entasse plusieurs classes dans un mme fichier, auquel cas Perl ne sait pas forcment quun paquetage spcifique tait

customer_8566

Construction dobjet

291

cens tre un nom de classe. Ceux qui nomment des fonctions avec des noms qui ressemblent NomsDeModule finissent galement par le regretter un jour ou lautre.

Construction dobjet
Tout objet est une rfrence, mais toute rfrence nest pas un objet. Une rfrence ne fonctionnera comme objet que si son rfrent est marqu spcialement pour dire Perl quel paquetage il appartient. On appelle consacrer (du sens anglais de la fonction bless) lacte de marquer un rfrent avec le nom dun paquetage et donc de sa classe, puisquune classe nest quun paquetage. Vous pouvez considrer que consacrer une rfrence la transforme en objet, bien quil soit plus prcis de dire que cela transforme la rfrence en rfrence un objet. La fonction bless prend un ou deux paramtres. Le premier paramtre est une rfrence et le deuxime est le paquetage avec lequel est consacr le rfrent. Si le deuxime paramtre est omis, cest le paquetage courant qui est utilis.
$obj = { }; # Obtenir une rfrence un hachage anonyme. bless($obj); # Consacrer le hachage avec le paquetage courant. bless($obj, "Bestiau"); # Consacrer le hachage avec la classe Bestiau.

Ici nous avons utilis une rfrence un hachage anonyme, ce que les gens utilisent habituellement comme structure de donnes pour leurs objets. Les hachages sont aprs tout extrmement f lexibles. Mais permettez-nous de souligner que vous pouvez consacrer une rfrence toute chose laquelle vous pouvez faire une rfrence en Perl, comme les scalaires, les tableaux, les fonctions et les typeglobs. Vous pouvez mme consacrer une rfrence au hachage de la table de symboles dun paquetage si vous trouvez une bonne raison de le faire. (Ou mme si vous nen trouvez pas.) Lorientation objet de Perl est entirement distincte de la structure des donnes. Une fois que le rfrent est consacr, lappel de la fonction interne ref sur sa rfrence retourne le nom de la classe consacre au lieu du type de base, comme HASH. Si vous vo