.\" Automatically generated by Pod::Man 2.09 (Pod::Simple 3.04) .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "PERLDSC 1" .TH PERLDSC 1 "2006-03-07" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Xref "structure de donne\*'es structure de donne\*'es complexes structure" .IX Header "NAME/NOM" perldsc \- Livre de recettes des structures de donne\*'es en Perl .SH "DESCRIPTION" .IX Header "DESCRIPTION" La seule caracte\*'ristique manquant cruellement au langage de programmation Perl avant sa version 5.0 e\*'tait les structures de donne\*'es complexes. Me\*^me sans support direct par le langage, certains programmeurs vaillants parvinrent a\*` les e\*'muler mais c'e\*'tait un dur travail, a\*` de\*'conseiller aux a\*^mes sensibles. Vous pouviez occasionnellement vous en sortir avec la notation \&\f(CW$m{$AoA,$b}\fR emprunte\*'e a\*` \fIawk\fR dans laquelle les cle\*'s sont en fait une seule chai\*^ne concate\*'ne\*'e \f(CW"$AoA$b"\fR, mais leurs parcours et leurs tris e\*'taient difficiles. Des programmeurs un peu plus de\*'sespe\*'re\*'s ont me\*^me directement bidouille\*' la table de symboles interne de Perl, une strate\*'gie qui s'est montre\*'e dure a\*` de\*'velopper et a\*` maintenir \- c'est le moins que l'on puisse dire. .PP La version 5.0 de Perl met a\*` notre disposition des structures de donne\*'es complexes. Vous pouvez maintenant e\*'crire quelque chose comme ce qui suit pour obtenir d'un seul coup un tableau a\*` trois dimensions\ ! .PP .Vb 8 \& for $x (1 .. 10) { \& for $y (1 .. 10) { \& for $z (1 .. 10) { \& $AoA[$x][$y][$z] = \& $x ** $y + $z; \& } \& } \& } .Ve .PP A\*` premie\*`re vue cette construction apparai\*^t simple, mais elle est en fait beaucoup plus complique\*'e qu'elle ne le laisse parai\*^tre\ ! .PP Comment pouvez-vous l'imprimer\ ? Pourquoi ne pouvez-vous pas juste dire \&\f(CW\*(C`print\ @AoA\*(C'\fR\ ? Comment la triez-vous\ ? Comment pouvez-vous la passer a\*` une fonction ou en re\*'cupe\*'rer une depuis une fonction\ ? Est-ce un objet\ ? Pouvez-vous la sauver sur disque pour la relire plus tard\ ? Comment acce\*'dez\-vous a\*` des lignes ou a\*` des colonnes entie\*`res de cette matrice\ ? Est-ce que toutes les valeurs doivent e\*^tre nume\*'riques\ ? .PP Comme vous le voyez, il est assez facile d'e\*^tre de\*'concerte\*'. Ces difficulte\*'s viennent, pour partie, de l'imple\*'mentation base\*'e sur les re\*'fe\*'rences mais aussi du manque de documentation proposant des exemples destine\*'s au de\*'butant. .PP Ce document est conc\*,u pour traiter, en de\*'tail mais de fac\*,on compre\*'hensible, toute une panoplie de structures de donne\*'es que vous pourriez e\*^tre amene\*' a\*` de\*'velopper. Il devrait aussi servir de livre de recettes donnant des exemples. De cette fac\*,on, lorsque vous avez besoin de cre\*'er l'une de ces structures de donne\*'es complexes, vous pouvez simplement piquer, chaparder ou de\*'rober un exemple de ce guide. .PP Jetons un oeil en de\*'tail a\*` chacune de ces constructions possibles. Il existe des sections se\*'pare\*'es pour chacun des cas suivants\ : .IP "\(bu" 5 tableaux de tableaux .IP "\(bu" 5 hachages de tableaux .IP "\(bu" 5 tableaux de hachages .IP "\(bu" 5 hachages de hachages .IP "\(bu" 5 constructions plus e\*'labore\*'es .PP Mais pour le moment, inte\*'ressons\-nous aux proble\*`mes communs a\*` tous ces types de structures de donne\*'es. .SH "RE\*'FE\*'RENCES" .IX Xref "re\*'fe\*'rence de\*'re\*'fe\*'rence de\*'re\*'fe\*'rencement pointeur" .IX Header "RE'FE'RENCES" La chose la plus importante a\*` comprendre au sujet de toutes les structures de donne\*'es en Perl \- y compris les tableaux multidimensionnels \- est que me\*^me s'ils peuvent parai\*^tre diffe\*'rents, les \f(CW@TABLEAU\fRx et les \f(CW%HACHAGE\fRs en Perl sont tous unidimensionnels en interne. Ils ne peuvent contenir que des valeurs scalaires (c'est\-a\*`\-dire une chai\*^ne, un nombre ou une re\*'fe\*'rence). Ils ne peuvent pas contenir directement d'autres tableaux ou hachages, mais ils contiennent a\*` la place des \fIre\*'fe\*'rences\fR a\*` des tableaux ou des hachages. .IX Xref "tableau multidimensionnel multidimensionnel, tableau" .PP Vous ne pouvez pas utiliser une re\*'fe\*'rence a\*` un tableau ou a\*` un hachage exactement de la me\*^me manie\*`re que vous le feriez d'un vrai tableau ou d'un vrai hachage. Pour les programmeurs C ou \*(C+, peu habitue\*'s a\*` distinguer les tableaux et les pointeurs vers des tableaux, ceci peut e\*^tre de\*'concertant. Si c'est le cas, conside\*'rez simplement la diffe\*'rence entre une structure et un pointeur vers une structure. .PP Vous pouvez (et devriez) en lire plus au sujet des re\*'fe\*'rences dans perlref. Brie\*`vement, les re\*'fe\*'rences ressemblent assez a\*` des pointeurs sachant vers quoi ils pointent (les objets sont aussi une sorte de re\*'fe\*'rence, mais nous n'en aurons pas besoin pour le moment). Ceci signifie que lorsque vous avez quelque chose qui vous semble e\*^tre un acce\*`s a\*` un tableau ou a\*` un hachage a\*` deux dimensions ou plus, ce qui se passe re\*'ellement est que le type de base est seulement une entite\*' unidimensionelle qui contient des re\*'fe\*'rences vers le niveau suivant. Vous pouvez juste l'\fIutiliser\fR comme si c'e\*'tait une entite\*' a\*` deux dimensions. C'est aussi en fait la fac\*,on dont fonctionnent presque tous les tableaux multidimensionnels en C. .PP .Vb 4 \& $array[7][12] # tableau de tableaux \& $array[7]{string} # tableau de hachages \& $hash{string}[7] # hachage de tableaux \& $hash{string}{'another string'} # hachage de hachages .Ve .PP Maintenant, puisque le niveau supe\*'rieur ne contient que des re\*'fe\*'rences, si vous essayez d'imprimer votre tableau avec une simple fonction \fIprint()\fR, vous obtiendrez quelque chose qui n'est pas tre\*`s joli, comme ceci\ : .PP .Vb 5 \& @AoA = ( [2, 3], [4, 5, 7], [0] ); \& print $AoA[1][2]; \& 7 \& print @AoA; \& ARRAY(0x83c38)ARRAY(0x8b194)ARRAY(0x8b1d0) .Ve .PP C'est parce que Perl ne de\*'re\*'fe\*'rence (presque) jamais implicitement vos variables. Si vous voulez atteindre la chose a\*` laquelle se re\*'fe\*`re une re\*'fe\*'rence, alors vous devez le faire vous\-me\*^me soit en utilisant des pre\*'fixes d'indication de type, comme \f(CW\*(C`${$blah}\*(C'\fR, \f(CW\*(C`@{$blah}\*(C'\fR, \f(CW\*(C`@{$blah[$i]}\*(C'\fR, soit des fle\*`ches de pointage postfixes, comme \f(CW\*(C`$a\->[3]\*(C'\fR, \f(CW\*(C`$h\->{fred}\*(C'\fR, ou me\*^me \f(CW\*(C`$ob\->method()\->[3]\*(C'\fR. .SH "ERREURS COURANTES" .IX Header "ERREURS COURANTES" Les deux erreurs les plus communes faites lors de l'affectation d'une donne\*'e de type tableau de tableaux est soit l'affectation du nombre d'e\*'le\*'ments du tableau (NdT\ : au lieu du tableau lui\-me\*^me bien su\*^r), soit l'affectation re\*'pe\*'te\*'e d'une me\*^me re\*'fe\*'rence me\*'moire. Voici le cas ou\*` vous obtenez juste le nombre d'e\*'le\*'ments au lieu d'un tableau imbrique\*'\ : .IX Xref "[] {}" .PP .Vb 4 \& for $i (1..10) { \& @list = somefunc($i); \& $AoA[$i] = @list; # FAUX ! \& } .Ve .PP C'est le cas simple ou\*` l'on affecte un tableau a\*` un scalaire et ou\*` l'on obtient le nombre de ses e\*'le\*'ments. Si c'est vraiment bien ce que vous de\*'sirez, alors vous pourriez e\*^tre un poil plus explicite a\*` ce sujet, comme ceci\ : .PP .Vb 4 \& for $i (1..10) { \& @array = somefunc($i); \& $counts[$i] = scalar @array; \& } .Ve .PP Voici le cas ou\*` vous vous re\*'fe\*'rez encore et encore au me\*^me emplacement me\*'moire\ : .PP .Vb 4 \& for $i (1..10) { \& @array = somefunc($i); \& $AoA[$i] = \e@array; # FAUX ! \& } .Ve .PP Allons bon, quel est le gros proble\*`me\ ? Cela semble bon, n'est\-ce pas\ ? Apre\*`s tout, je viens de vous dire que vous aviez besoin d'un tableau de re\*'fe\*'rences, alors flu\*^te, vous m'en avez cre\*'e\*' un\ ! .PP Malheureusement, bien que cela soit vrai, cela ne marche pas. Toutes les re\*'fe\*'rences dans \f(CW@AoA\fR se re\*'fe\*`re au \fIme\*^me endroit\fR, et elles contiendront toutes par conse\*'quent ce qui se trouvait en dernier dans \&\f(CW@array\fR\ ! Le proble\*`me est similaire a\*` celui du programme C suivant\ : .PP .Vb 5 \& #include \& main() { \& struct passwd *getpwnam(), *rp, *dp; \& rp = getpwnam("root"); \& dp = getpwnam("daemon"); \& \& printf("daemon name is %s\enroot name is %s\en", \& dp\->pw_name, rp\->pw_name); \& } .Ve .PP Ce qui affichera\ : .PP .Vb 2 \& daemon name is daemon \& root name is daemon .Ve .PP Le proble\*`me est que \f(CW\*(C`rp\*(C'\fR et \f(CW\*(C`dp\*(C'\fR sont des pointeurs vers le me\*^me emplacement en me\*'moire\ ! En C, vous devez utiliser \fImalloc()\fR pour vous re\*'server de la me\*'moire. En Perl, vous devez utiliser a\*` la place le constructeur de tableau \f(CW\*(C`[]\*(C'\fR ou le constructeur de hachages \&\f(CW\*(C`{}\*(C'\fR. Voici la bonne fac\*,on de proce\*'der\ : .PP .Vb 4 \& for $i (1..10) { \& @array = somefunc($i); \& $AoA[$i] = [ @array ]; \& } .Ve .PP Les crochets cre\*'ent une re\*'fe\*'rence a\*` un nouveau tableau avec une \&\fIcopie\fR de ce qui se trouve dans \f(CW@array\fR au moment de l'affectation. C'est ce que vous de\*'siriez. .PP Notez que ceci produira quelque chose de similaire, mais c'est bien plus dur a\*` lire\ : .PP .Vb 4 \& for $i (1..10) { \& @array = 0 .. $i; \& @{$AoA[$i]} = @array; \& } .Ve .PP Est-ce la me\*^me chose\ ? Eh bien, peut\-e\*^tre que oui, peut\-e\*^tre que non. La diffe\*'rence subtile est que lorsque vous affectez quelque chose entre crochets, vous e\*^tes su\*^r que ce sera toujours une nouvelle re\*'fe\*'rence contenant une nouvelle \fIcopie\fR des donne\*'es. C\*,a ne se passera pas force\*'ment comme c\*,a avec le de\*'re\*'fe\*'rencement \f(CW\*(C`@{$AoA[$i]}}\*(C'\fR du co\*^te\*' gauche de l'affectation. Tout de\*'pend si \f(CW$AoA[$i]\fR e\*'tait pour commencer inde\*'fini, ou s'il contenait de\*'ja\*` une re\*'fe\*'rence. Si vous aviez de\*'ja\*` peuple\*' \f(CW@AoA\fR avec des re\*'fe\*'rences, comme dans .PP .Vb 1 \& $AoA[3] = \e@another_array; .Ve .PP alors l'affectation avec l'indirection du co\*^te\*' gauche utiliserait la re\*'fe\*'rence existante de\*'ja\*` pre\*'sente\ : .PP .Vb 1 \& @{$AoA[3]} = @array; .Ve .PP Bien su\*^r, ceci \fIaurait\fR l'effet \*(L"inte\*'ressant\*(R" de de\*'molir \&\f(CW@another_list\fR (Avez\-vous de\*'ja\*` remarque\*' que lorsqu'un programmeur dit que quelque chose est \*(L"inte\*'ressant\*(R", au lieu de dire \*(L"intrigant\*(R", alors c\*,a signifie que c'est \*(L"ennuyeux\*(R", \*(L"difficile\*(R", ou les deux\ ? :\-). .PP Donc, souvenez-vous juste de toujours utiliser le constructeur de tableau ou de hachage \f(CW\*(C`[]\*(C'\fR ou \f(CW\*(C`{}\*(C'\fR et tout ira bien pour vous, me\*^me si ce n'est pas la solution optimale. .PP De fac\*,on surprenante, la construction suivante qui a l'air dangereuse marchera en fait tre\*`s bien\ : .PP .Vb 4 \& for $i (1..10) { \& my @array = somefunc($i); \& $AoA[$i] = \e@array; \& } .Ve .PP C'est parce que \fImy()\fR est plus une expression utilise\*'e lors de l'exe\*'cution qu'une de\*'claration de compilation \fIen elle\-me\*^me\fR. Cela signifie que la variable \fImy()\fR est recre\*'e\*'e de ze\*'ro chaque fois que l'on traverse la boucle. Donc me\*^me si on a \fIl'impression\fR que vous stockez la me\*^me re\*'fe\*'rence de variable a\*` chaque fois, ce n'est pas le cas\ ! C'est une distinction subtile qui peut produire un code plus efficace au risque de tromper tous les programmeurs sauf les plus expe\*'rimente\*'s. Je de\*'conseille donc habituellement de l'enseigner aux de\*'butants. En fait, sauf pour passer des arguments a\*` des fonctions, j'aime rarement voir l'ope\*'rateur \*(L"donne\-moi\-une\-re\*'fe\*'rence\*(R" (backslash) utilise\*' dans du code. A\*` la place, je conseille aux de\*'butants (et a\*` la plupart d'entre nous) d'essayer d'utiliser les constructeurs bien plus compre\*'hensibles \&\f(CW\*(C`[]\*(C'\fR et \f(CW\*(C`{}\*(C'\fR au lieu de se reposer sur une astuce lexicale (ou dynamique) et un comptage de re\*'fe\*'rence cache\*' pour faire ce qu'il faut en coulisses. .PP En re\*'sume\*'\ : .PP .Vb 5 \& $AoA[$i] = [ @array ]; # habituellement mieux \& $AoA[$i] = \e@array; # perilleux ; tableau declare \& # avec my() ? Comment ? \& @{ $AoA[$i] } = @array; # bien trop astucieux pour la plupart \& # des programmeurs .Ve .SH "AVERTISSEMENT SUR LA PRE\*'CE\*'DENCE" .IX Xref "de\*'re\*'fe\*'rencement, pre\*'ce\*'dence de\*'re\*'fe\*'rencement, priorite\*'" .IX Header "AVERTISSEMENT SUR LA PRE'CE'DENCE" En parlant de choses comme \f(CW\*(C`@{$AoA[$i]}\*(C'\fR, les expressions suivantes sont en fait e\*'quivalentes\ : .IX Xref "->" .PP .Vb 2 \& $aref\->[2][2] # clair \& $$aref[2][2] # troublant .Ve .PP C'est du\*^ aux re\*`gles de pre\*'ce\*'dence de Perl qui rend les cinq pre\*'fixes de\*'re\*'fe\*'renceurs (qui ont l'air de jurons\ : \f(CW\*(C`$ @ * % &\*(C'\fR) plus prioritaires que les accolades et les crochets d'indic\*,age postfixes\ ! Ceci sera sans doute un grand choc pour le programmeur C ou \*(C+, qui est habitue\*' a\*` utiliser \f(CW*a[i]\fR pour indiquer ce qui est pointe\*' par le \&\fIi\-e\*`me\fR e\*'le\*'ment de \f(CW\*(C`a\*(C'\fR. C'est\-a\*`\-dire qu'ils prennent d'abord l'indice, et ensuite seulement de\*'re\*'fe\*'rencent la structure a\*` cet indice. C'est bien en C, mais nous ne parlons pas de C. .PP La construction apparemment e\*'quivalente en Perl, \f(CW$$aref[$i]\fR commence par de\*'re\*'fe\*'rencer \f(CW$aref\fR, le faisant prendre \f(CW$aref\fR comme une re\*'fe\*'rence a\*` un tableau, et puis de\*'re\*'fe\*'rence cela, et finalement vous donne la valeur du \fIi\-e\*`me\fR e\*'le\*'ment du tableau pointe\*' par \f(CW$AoA\fR. Si vous vouliez la notion e\*'quivalente en C, vous devriez e\*'crire \f(CW\*(C`${$AoA[$i]}\*(C'\fR pour forcer l'e\*'valuation de \f(CW$AoA[$i]\fR avant le premier de\*'re\*'fe\*'renceur \f(CW\*(C`$\*(C'\fR. .ie n .SH "POURQUOI TOUJOURS UTILISER ""use strict""" .el .SH "POURQUOI TOUJOURS UTILISER \f(CWuse strict\fP" .IX Header "POURQUOI TOUJOURS UTILISER use strict" Ce n'est pas aussi effrayant que c\*,a en a l'air, de\*'tendez\-vous. Perl posse\*`de un certain nombre de caracte\*'ristiques qui vont vous aider a\*` e\*'viter les pie\*`ges les plus communs. La meilleure fac\*,on de ne pas e\*^tre trouble\*' est de commencer les programmes ainsi\ : .PP .Vb 2 \& #!/usr/bin/perl \-w \& use strict; .Ve .PP De cette fac\*,on, vous serez force\*' de de\*'clarer toutes vos variables avec \&\fImy()\fR et aussi d'interdire tout \*(L"de\*'re\*'fe\*'rencement symbolique\*(R" accidentel. Par conse\*'quent, si vous faites ceci\ : .PP .Vb 5 \& my $aref = [ \& [ "fred", "barney", "pebbles", "bambam", "dino", ], \& [ "homer", "bart", "marge", "maggie", ], \& [ "george", "jane", "elroy", "judy", ], \& ]; \& \& print $aref[2][2]; .Ve .PP Le compilateur marquera imme\*'diatement ceci comme une erreur \fIlors de la compilation\fR, car vous acce\*'dez accidentellement a\*` \f(CW@aref\fR qui est une variable non de\*'clare\*'e, et il vous proposerait d'e\*'crire a\*` la place\ : .PP .Vb 1 \& print $aref\->[2][2] .Ve .SH "DE\*'BOGAGE" .IX Xref "structure de donne\*'es, de\*'bogage structure de donne\*'es complexe, de\*'bogage LdL, de\*'bogage HdL, de\*'bogage LdH, de\*'bogage HdH, de\*'bogage tableau de tableaux, de\*'bogage hachage de tableaux, de\*'bogage tableau de hachages, de\*'bogage hachage de hachages, de\*'bogage" .IX Header "DE'BOGAGE" Avant la version 5.002, le de\*'bogueur standard de Perl ne faisait pas un tre\*`s bon travail lorsqu'il devait imprimer des structures de donne\*'es complexes. Avec la version 5.002 et les suivantes, le de\*'bogueur inclut plusieurs nouvelles caracte\*'ristiques, dont une e\*'dition de la ligne de commande ainsi que la commande \f(CW\*(C`x\*(C'\fR pour afficher les structures de donne\*'es complexes. Par exemple, voici la sortie du de\*'bogueur avec l'affectation a\*` \f(CW$AoA\fR ci-dessus\ : .PP .Vb 10 \& DB<1> x $AoA \& $AoA = ARRAY(0x13b5a0) \& 0 ARRAY(0x1f0a24) \& 0 'fred' \& 1 'barney' \& 2 'pebbles' \& 3 'bambam' \& 4 'dino' \& 1 ARRAY(0x13b558) \& 0 'homer' \& 1 'bart' \& 2 'marge' \& 3 'maggie' \& 2 ARRAY(0x13b540) \& 0 'george' \& 1 'jane' \& 2 'elroy' \& 3 'judy' .Ve .SH "EXEMPLES DE CODE" .IX Header "EXEMPLES DE CODE" Pre\*'sente\*'s avec peu de commentaires (ils auront leurs propres pages de manuel un jour), voici de courts exemples de code illustrant l'acce\*`s a\*` divers types de structures de donne\*'es. .SH "TABLEAUX DE TABLEAUX" .IX Xref "tableau de tableaux TdT" .IX Header "TABLEAUX DE TABLEAUX" .Sh "De\*'claration d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "De'claration d'un TABLEAU DE TABLEAUX" .Vb 5 \& @AoA = ( \& [ "fred", "barney" ], \& [ "george", "jane", "elroy" ], \& [ "homer", "marge", "bart" ], \& ); .Ve .Sh "Ge\*'ne\*'ration d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "Ge'ne'ration d'un TABLEAU DE TABLEAUX" .Vb 4 \& # lecture dans un fichier \& while ( <> ) { \& push @AoA, [ split ]; \& } \& \& # appel d'une function \& for $i ( 1 .. 10 ) { \& $AoA[$i] = [ somefunc($i) ]; \& } \& \& # utilisation de variables temporaires \& for $i ( 1 .. 10 ) { \& @tmp = somefunc($i); \& $AoA[$i] = [ @tmp ]; \& } \& \& # ajout dans une range\*'e existante \& push @{ $AoA[0] }, "wilma", "betty"; .Ve .Sh "Acce\*`s et affichage d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "Acce`s et affichage d'un TABLEAU DE TABLEAUX" .Vb 2 \& # un element \& $AoA[0][0] = "Fred"; \& \& # un autre element \& $AoA[1][1] =~ s/(\ew)/\eu$1/; \& \& # affiche le tout avec des refs \& for $aref ( @AoA ) { \& print "\et [ @$aref ],\en"; \& } \& \& # affiche le tout avec des indices \& for $i ( 0 .. $#AoA ) { \& print "\et [ @{$AoA[$i]} ],\en"; \& } \& \& # affiche tous les elements un par un \& for $i ( 0 .. $#AoA ) { \& for $j ( 0 .. $#{ $AoA[$i] } ) { \& print "elt $i $j is $AoA[$i][$j]\en"; \& } \& } .Ve .SH "HACHAGE DE TABLEAUX" .IX Xref "hachage de tableaux HdT" .IX Header "HACHAGE DE TABLEAUX" .Sh "De\*'claration d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "De'claration d'un HACHAGE DE TABLEAUX" .Vb 5 \& %HoA = ( \& flintstones => [ "fred", "barney" ], \& jetsons => [ "george", "jane", "elroy" ], \& simpsons => [ "homer", "marge", "bart" ], \& ); .Ve .Sh "Ge\*'ne\*'ration d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "Ge'ne'ration d'un HACHAGE DE TABLEAUX" .Vb 6 \& # lecture dans un fichier \& # flintstones: fred barney wilma dino \& while ( <> ) { \& next unless s/^(.*?):\es*//; \& $HoA{$1} = [ split ]; \& } \& \& # lecture dans un fichier avec plus de variables temporaires \& # flintstones: fred barney wilma dino \& while ( $line = <> ) { \& ($who, $rest) = split /:\es*/, $line, 2; \& @fields = split ' ', $rest; \& $HoA{$who} = [ @fields ]; \& } \& \& # appel d'une fonction qui retourne une liste \& for $group ( "simpsons", "jetsons", "flintstones" ) { \& $HoA{$group} = [ get_family($group) ]; \& } \& \& # idem, mais en utilisant des variables temporaires \& for $group ( "simpsons", "jetsons", "flintstones" ) { \& @members = get_family($group); \& $HoA{$group} = [ @members ]; \& } \& \& # ajout de nouveaux membres a une famille existante \& push @{ $HoA{"flintstones"} }, "wilma", "betty"; .Ve .Sh "Acce\*`s et affichage d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1TABLEAUX\s0" .IX Subsection "Acce`s et affichage d'un HACHAGE DE TABLEAUX" .Vb 2 \& # un element \& $HoA{flintstones}[0] = "Fred"; \& \& # un autre element \& $HoA{simpsons}[1] =~ s/(\ew)/\eu$1/; \& \& # affichage du tout \& foreach $family ( keys %HoA ) { \& print "$family: @{ $HoA{$family} }\en" \& } \& \& # affichage du tout avec des indices \& foreach $family ( keys %HoA ) { \& print "family: "; \& foreach $i ( 0 .. $#{ $HoA{$family} } ) { \& print " $i = $HoA{$family}[$i]"; \& } \& print "\en"; \& } \& \& # affichage du tout trie par le nombre de membres \& foreach $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) { \& print "$family: @{ $HoA{$family} }\en" \& } \& \& # affichage du tout trie par le nombre de membres et le nom \& foreach $family ( sort { \& @{$HoA{$b}} <=> @{$HoA{$a}} \& || \& $a cmp $b \& } keys %HoA ) \& { \& print "$family: ", join(", ", sort @{ $HoA{$family} }), "\en"; \& } .Ve .SH "TABLEAUX DE HACHAGES" .IX Xref "tableau de hachages TdH" .IX Header "TABLEAUX DE HACHAGES" .Sh "De\*'claration d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "De'claration d'un TABLEAU DE HACHAGES" .Vb 10 \& @AoH = ( \& { \& Lead => "fred", \& Friend => "barney", \& }, \& { \& Lead => "george", \& Wife => "jane", \& Son => "elroy", \& }, \& { \& Lead => "homer", \& Wife => "marge", \& Son => "bart", \& } \& ); .Ve .Sh "Ge\*'ne\*'ration d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "Ge'ne'ration d'un TABLEAU DE HACHAGES" .Vb 10 \& # lecture dans un fichier \& # format : LEAD=fred FRIEND=barney \& while ( <> ) { \& $rec = {}; \& for $field ( split ) { \& ($key, $value) = split /=/, $field; \& $rec\->{$key} = $value; \& } \& push @AoH, $rec; \& } \& \& # lecture dans un fichier sans variable temporaire \& # format: LEAD=fred FRIEND=barney \& while ( <> ) { \& push @AoH, { split /[\es+=]/ }; \& } \& \& # appel d'une fonction qui retourne une liste cle\*'/valeur, comme \& # "lead","fred","daughter","pebbles" \& while ( %fields = getnextpairset() ) { \& push @AoH, { %fields }; \& } \& \& # idem, mais sans variables temporaires \& while (<>) { \& push @AoH, { parsepairs($_) }; \& } \& \& # ajout d'un couple cle\*'/valeur a\*` un element \& $AoH[0]{pet} = "dino"; \& $AoH[2]{pet} = "santa's little helper"; .Ve .Sh "Acce\*`s et affichage d'un \s-1TABLEAU\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "Acce`s et affichage d'un TABLEAU DE HACHAGES" .Vb 2 \& # un element \& $AoH[0]{lead} = "fred"; \& \& # un autre element \& $AoH[1]{lead} =~ s/(\ew)/\eu$1/; \& \& # affichage du tout avec des refs \& for $href ( @AoH ) { \& print "{ "; \& for $role ( keys %$href ) { \& print "$role=$href\->{$role} "; \& } \& print "}\en"; \& } \& \& # affichage du tout avec des indices \& for $i ( 0 .. $#AoH ) { \& print "$i is { "; \& for $role ( keys %{ $AoH[$i] } ) { \& print "$role=$AoH[$i]{$role} "; \& } \& print "}\en"; \& } \& \& # affichage du tout element par element \& for $i ( 0 .. $#AoH ) { \& for $role ( keys %{ $AoH[$i] } ) { \& print "elt $i $role is $AoH[$i]{$role}\en"; \& } \& } .Ve .SH "HACHAGES DE HACHAGES" .IX Xref "hachage de hachages HdH" .IX Header "HACHAGES DE HACHAGES" .Sh "De\*'claration d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "De'claration d'un HACHAGE DE HACHAGES" .Vb 10 \& %HoH = ( \& flintstones => { \& lead => "fred", \& pal => "barney", \& }, \& jetsons => { \& lead => "george", \& wife => "jane", \& "his boy" => "elroy", \& }, \& simpsons => { \& lead => "homer", \& wife => "marge", \& kid => "bart", \& }, \& ); .Ve .Sh "Ge\*'ne\*'ration d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "Ge'ne'ration d'un HACHAGE DE HACHAGES" .Vb 9 \& # lecture dans un fichier \& # flintstones: lead=fred pal=barney wife=wilma pet=dino \& while ( <> ) { \& next unless s/^(.*?):\es*//; \& $who = $1; \& for $field ( split ) { \& ($key, $value) = split /=/, $field; \& $HoH{$who}{$key} = $value; \& } \& \& # lecture dans un fichier, encore plus de variables temporaires \& while ( <> ) { \& next unless s/^(.*?):\es*//; \& $who = $1; \& $rec = {}; \& $HoH{$who} = $rec; \& for $field ( split ) { \& ($key, $value) = split /=/, $field; \& $rec\->{$key} = $value; \& } \& } \& \& # appel d'une fonction qui retourne un hachage cle\*'/valeur \& for $group ( "simpsons", "jetsons", "flintstones" ) { \& $HoH{$group} = { get_family($group) }; \& } \& \& # idem, mais en utilisant des variables temporaires \& for $group ( "simpsons", "jetsons", "flintstones" ) { \& %members = get_family($group); \& $HoH{$group} = { %members }; \& } \& \& # ajout de nouveaux membres a une famille existante \& %new_folks = ( \& wife => "wilma", \& pet => "dino", \& ); \& \& for $what (keys %new_folks) { \& $HoH{flintstones}{$what} = $new_folks{$what}; \& } .Ve .Sh "Acce\*`s et affichage d'un \s-1HACHAGE\s0 \s-1DE\s0 \s-1HACHAGES\s0" .IX Subsection "Acce`s et affichage d'un HACHAGE DE HACHAGES" .Vb 2 \& # un element \& $HoH{flintstones}{wife} = "wilma"; \& \& # un autre element \& $HoH{simpsons}{lead} =~ s/(\ew)/\eu$1/; \& \& # affichage du tout \& foreach $family ( keys %HoH ) { \& print "$family: { "; \& for $role ( keys %{ $HoH{$family} } ) { \& print "$role=$HoH{$family}{$role} "; \& } \& print "}\en"; \& } \& \& # affichage du tout un peu trie \& foreach $family ( sort keys %HoH ) { \& print "$family: { "; \& for $role ( sort keys %{ $HoH{$family} } ) { \& print "$role=$HoH{$family}{$role} "; \& } \& print "}\en"; \& } \& \& # affichage du tout trie par le nombre de membres \& foreach $family ( sort { keys %{$HoH{$b}} <=> keys %{$HoH{$a}} } keys %HoH ) { \& print "$family: { "; \& for $role ( sort keys %{ $HoH{$family} } ) { \& print "$role=$HoH{$family}{$role} "; \& } \& print "}\en"; \& } \& \& # etablissement d'un ordre de tri (rang) pour chaque role \& $i = 0; \& for ( qw(lead wife son daughter pal pet) ) { $rank{$_} = ++$i } \& \& # maintenant affiche le tout trie par le nombre de membres \& foreach $family ( sort { keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } } keys %HoH ) { \& print "$family: { "; \& # et affichage selon l'ordre de tri (rang) \& for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} } ) { \& print "$role=$HoH{$family}{$role} "; \& } \& print "}\en"; \& } .Ve .SH "ENREGISTREMENTS PLUS E\*'LABORE\*'S" .IX Xref "enregistrement structure" .IX Header "ENREGISTREMENTS PLUS E'LABORE'S" .Sh "De\*'claration d'\s-1ENREGISTREMENTS\s0 \s-1PLUS\s0 E\*'LABORE\*'S" .IX Subsection "De'claration d'ENREGISTREMENTS PLUS E'LABORE'S" Voici un exemple montrant comment cre\*'er et utiliser un enregistrement dont les champs sont de types diffe\*'rents\ : .PP .Vb 8 \& $rec = { \& TEXT => $string, \& SEQUENCE => [ @old_values ], \& LOOKUP => { %some_table }, \& THATCODE => \e&some_function, \& THISCODE => sub { $_[0] ** $_[1] }, \& HANDLE => \e*STDOUT, \& }; \& \& print $rec\->{TEXT}; \& \& print $rec\->{SEQUENCE}[0]; \& $last = pop @ { $rec\->{SEQUENCE} }; \& \& print $rec\->{LOOKUP}{"key"}; \& ($first_k, $first_v) = each %{ $rec\->{LOOKUP} }; \& \& $answer = $rec\->{THATCODE}\->($arg); \& $answer = $rec\->{THISCODE}\->($arg1, $arg2); \& \& # attention aux accolades de bloc supplementaires sur la ref fh \& print { $rec\->{HANDLE} } "a string\en"; \& \& use FileHandle; \& $rec\->{HANDLE}\->autoflush(1); \& $rec\->{HANDLE}\->print(" a string\en"); .Ve .Sh "De\*'claration d'un \s-1HACHAGE\s0 D'\s-1ENREGISTREMENTS\s0 \s-1COMPLEXES\s0" .IX Subsection "De'claration d'un HACHAGE D'ENREGISTREMENTS COMPLEXES" .Vb 10 \& %TV = ( \& flintstones => { \& series => "flintstones", \& nights => [ qw(monday thursday friday) ], \& members => [ \& { name => "fred", role => "lead", age => 36, }, \& { name => "wilma", role => "wife", age => 31, }, \& { name => "pebbles", role => "kid", age => 4, }, \& ], \& }, \& \& jetsons => { \& series => "jetsons", \& nights => [ qw(wednesday saturday) ], \& members => [ \& { name => "george", role => "lead", age => 41, }, \& { name => "jane", role => "wife", age => 39, }, \& { name => "elroy", role => "kid", age => 9, }, \& ], \& }, \& \& simpsons => { \& series => "simpsons", \& nights => [ qw(monday) ], \& members => [ \& { name => "homer", role => "lead", age => 34, }, \& { name => "marge", role => "wife", age => 37, }, \& { name => "bart", role => "kid", age => 11, }, \& ], \& }, \& ); .Ve .Sh "Ge\*'ne\*'ration d'un \s-1HACHAGE\s0 D'\s-1ENREGISTREMENTS\s0 \s-1COMPLEXES\s0" .IX Subsection "Ge'ne'ration d'un HACHAGE D'ENREGISTREMENTS COMPLEXES" .Vb 6 \& # lecture d'un fichier \& # c'est plus facile a faire quand on dispose du fichier lui\-meme \& # dans le format de donnees brut explicite ci\-dessus. perl analyse \& # joyeusement les structures de donnees complexes si elles sont \& # declarees comme des donnees, il est donc parfois plus facile de \& # faire ceci \& \& # voici un assemblage morceau par morceau \& $rec = {}; \& $rec\->{series} = "flintstones"; \& $rec\->{nights} = [ find_days() ]; \& \& @members = (); \& # on presume que ce fichier a la syntaxe champ=valeur \& while (<>) { \& %fields = split /[\es=]+/; \& push @members, { %fields }; \& } \& $rec\->{members} = [ @members ]; \& \& # maintenant on se rappelle du tout \& $TV{ $rec\->{series} } = $rec; \& \& ########################################################### \& # maintenant, vous pourriez vouloir creer des champs \& # supplementaires interessants incluant des pointeurs vers \& # l'interieur de cette meme structure de donnees pour que \& # si l'on en change un morceau, il se retrouve change partout \& # ailleurs, comme par exemple un champ {kids} (enfants, NDT) \& # qui serait une reference vers un tableau des enregistrements \& # des enfants, sans avoir d'enregistrements dupliques et donc \& # des soucis de mise a jour. \& ########################################################### \& foreach $family (keys %TV) { \& $rec = $TV{$family}; # pointeur temporaire \& @kids = (); \& for $person ( @{ $rec\->{members} } ) { \& if ($person\->{role} =~ /kid|son|daughter/) { \& push @kids, $person; \& } \& } \& # SOUVENEZ\-VOUS : $rec et $TV{$family} pointent sur les memes donnees !! \& $rec\->{kids} = [ @kids ]; \& } \& \& # vous avez copie le tableau, mais le tableau lui\-meme contient des \& # pointeurs vers des objets qui n'ont pas e\*'te\*' copie\*'s. Cela veut \& # dire que si vous vieillissez bart en faisant \& \& $TV{simpsons}{kids}[0]{age}++; \& \& # alors c\*,a changerait aussi \& print $TV{simpsons}{members}[2]{age}; \& \& # car $TV{simpsons}{kids}[0] et $TV{simpsons}{members}[2] \& # pointent tous deux vers la meme table de hachage anonyme sous\-jacente \& \& # imprime le tout \& foreach $family ( keys %TV ) { \& print "the $family"; \& print " is on during @{ $TV{$family}{nights} }\en"; \& print "its members are:\en"; \& for $who ( @{ $TV{$family}{members} } ) { \& print " $who\->{name} ($who\->{role}), age $who\->{age}\en"; \& } \& print "it turns out that $TV{$family}{lead} has "; \& print scalar ( @{ $TV{$family}{kids} } ), " kids named "; \& print join (", ", map { $_\->{name} } @{ $TV{$family}{kids} } ); \& print "\en"; \& } .Ve .SH "Liens avec les bases de donne\*'es" .IX Header "Liens avec les bases de donne'es" Il n'est pas possible de lier facilement une structure de donne\*'es multiniveaux (tel qu'un hachage de hachages) a\*` un fichier de base de donne\*'es (fichier dbm). Le premier proble\*`me est que tous ces fichiers, a\*` l'exception des \s-1GBM\s0 et des \s-1DB\s0 de Berkeley, ont des limitations de taille, mais il y a d'autres proble\*`mes du\*^s la manie\*`re dont les re\*'fe\*'rences sont repre\*'sente\*'es sur le disque. Il existe un module expe\*'rimental, le module \s-1MLDBM\s0, qui essaye de combler partiellement ce besoin. Pour obtenir le code source du module \s-1MLDBM\s0 allez voir sur le site \&\s-1CPAN\s0 le plus proche comme de\*'crit dans perlmodlib. .SH "VOIR AUSSI" .IX Header "VOIR AUSSI" perlref, perllol, perldata et perlobj. .SH "AUTEUR" .IX Header "AUTEUR" Tom Christiansen <\fItchrist@perl.com\fR> .PP Dernie\*`re mise a\*` jour\ : Wed Oct 23 04:57:50 \s-1MET\s0 \s-1DST\s0 1996 .SH "TRADUCTION" .IX Header "TRADUCTION" .Sh "Version" .IX Subsection "Version" Cette traduction franc\*,aise correspond a\*` la version anglaise distribue\*'e avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez . .Sh "Traducteur" .IX Subsection "Traducteur" Roland Trique <\fIroland.trique@free.fr\fR> .Sh "Relecture" .IX Subsection "Relecture" Pascal Ethvignot <\fIpascal@encelade.frmug.org\fR>, Etienne Gauthier <\fIegauthie@capgemini.fr\fR>, Paul Gaborit (Paul.Gaborit @ enstimac.fr).