.\" 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 "PERLFAQ4 1" .TH PERLFAQ4 1 "2006-04-03" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Header "NAME/NOM" perlfaq4 \- Manipulation de donne\*'es ($Revision: 1.73 $, \f(CW$Date:\fR 2005/12/31 00:54:37 $) .SH "DESCRIPTION" .IX Header "DESCRIPTION" Cette section de la \s-1FAQ\s0 re\*'pond aux questions lie\*'es a\*` la manipulation des nombres, des dates, des chai\*^nes de caracte\*`res, des tableaux, des tables de hachage, ainsi qu'a\*` divers proble\*`mes relatifs aux donne\*'es. .SH "Donne\*'es\ : nombres" .IX Header "Donne'es: nombres" .Sh "Pourquoi est-ce que j'obtiens des longs nombres de\*'cimaux (ex. 19.9499999999999) a\*` la place du nombre que j'attends (ex. 19.95)\ ?" .IX Subsection "Pourquoi est-ce que j'obtiens des longs nombres de'cimaux (ex. 19.9499999999999) a` la place du nombre que j'attends (ex. 19.95)?" En interne, un ordinateur repre\*'sente les flottants (les nombres a\*` virgule) sous forme binaire. Les ordinateurs ne peuvent pas stocker tous les nombres de manie\*`re exacte. Certains nombres re\*'els perdent un peu de pre\*'cision lors de leur traitement. C'est un proble\*`me du\*^ a\*` la manie\*`re dont les ordinateurs stockent les nombres et concerne donc tous les langages, pas uniquement Perl. .PP Voir perlnumber pour de plus amples informations sur le stockage des nombres et leurs conversions. .PP Pour limiter le nombre de de\*'cimales dans un nombre, vous pouvez utiliser les fonctions printf ou sprintf. Voir perlop pour plus de de\*'tails. .PP .Vb 1 \& printf "%.2f", 10/3; \& \& my $number = sprintf "%.2f", 10/3; .Ve .Sh "Pourquoi \fIint()\fP ne fonctionne pas bien\ ?" .IX Subsection "Pourquoi int() ne fonctionne pas bien?" Votre fonction \fIint()\fR fonctionne certainement tre\*`s bien. Ce sont les nombres qui ne sont pas ce que vous croyez. .PP Tout d'abord, voyez la question ci-dessus perlfaq4. .PP Par exemple, ceci\ : .PP .Vb 1 \& print int(0.6/0.2\-2), "\en"; .Ve .PP affichera 0 et non 1 sur la plupart des ordinateurs, puisque me\*^me des nombres aussi simples que 0.6 et 0.2 ne peuvent pas e\*^tre repre\*'sente\*'s exactement par des flottants. Ce que vous espe\*'riez e\*^tre 'trois' ci-dessus et en fait quelque chose comme 2.9999999999999995559. .Sh "Pourquoi mon nombre octal n'est\-il pas interpre\*'te\*' correctement\ ?" .IX Subsection "Pourquoi mon nombre octal n'est-il pas interpre'te' correctement?" Perl ne comprend les nombres octaux et hexade\*'cimaux en tant que tels que lorsqu'ils sont utilise\*'s comme des valeurs litte\*'rales dans le programme. En Perl, les nombres octaux litte\*'raux doivent commencer par \&\*(L"0\*(R" et les hexade\*'cimaux par \*(L"0x\*(R". S'ils sont lus de quelque part et affecte\*'s a\*` une variable, aucune conversion automatique n'a lieu. Pour convertir les valeurs, il faut utiliser explicitement \fIoct()\fR ou \&\fIhex()\fR. \fIoct()\fR interpre\*`te a\*` la fois les nombres hexade\*'cimaux (\*(L"0x350\*(R"), les nombres octaux (\*(L"0350\*(R" ou me\*^me sans le \*(L"0\*(R" de te\*^te, comme dans \&\*(L"377\*(R") et les nombres binaires (\*(L"0b1010\*(R"), tandis que \fIhex()\fR ne convertit que les hexade\*'cimaux, avec ou sans l'en\-te\*^te \*(L"0x\*(R", comme pour \*(L"0x255\*(R", \*(L"3A\*(R", \*(L"ff\*(R", ou \*(L"baffe\*(R". Le transformation inverse (depuis de\*'cimal vers octal) peut e\*^tre obtenue via les formats \*(L"%o\*(R" et \&\*(L"%O\*(R" de \fIsprintf()\fR. .PP Ce proble\*`me apparai\*^t fre\*'quemment lorsque l'on essaye d'utiliser les fonctions \fIchmod()\fR, \fImkdir()\fR, \fIumask()\fR, ou \fIsysopen()\fR qui demandent toutes traditionnellement des permissions en octal. .PP .Vb 2 \& chmod(644, $file); # FAUX \& chmod(0644, $file); # correct .Ve .PP Notez l'erreur de la premie\*`re ligne qui spe\*'cifie le nombre de\*'cimal 644 au lieu du nombre octal voulu 0644. Le proble\*`me apparai\*^t mieux avec\ : .PP .Vb 1 \& printf("%#o",644); # affiche 01204 .Ve .PP Vous ne vouliez pas dire \f(CW\*(C`chmod(01204, $file)\*(C'\fR... Si vous voulez utilisez des valeurs nume\*'riques octales comme arguments de \fIchmod()\fR et autres, alors exprimez les en les pre\*'fixant d'un ze\*'ro et en n'utilisant ensuite que des chiffres de 0 a\*` 7. .Sh "Perl a\-t-il une fonction \fIround()\fP\ ? Et \fIceil()\fP (majoration) et \fIfloor()\fP (minoration)\ ? Et des fonctions trigonome\*'triques\ ?" .IX Subsection "Perl a-t-il une fonction round()? Et ceil() (majoration) et floor() (minoration)? Et des fonctions trigonome'triques?" Il faut retenir que \fIint()\fR ne fait que tronquer vers 0. Pour arrondir a\*` un certain nombre de chiffres, \fIsprintf()\fR ou \fIprintf()\fR sont d'habitude la voie la plus simple. .PP .Vb 1 \& printf("%.3f", 3.1415926535); # affiche 3.142 .Ve .PP Le module \s-1POSIX\s0 (e\*'le\*'ment de la distribution standard de Perl) imple\*'mente \fIceil()\fR, \fIfloor()\fR, et d'autres fonctions mathe\*'matiques et trigonome\*'triques. .PP .Vb 3 \& use POSIX; \& $ceil = ceil(3.5); # 4 \& $floor = floor(3.5); # 3 .Ve .PP Dans les versions 5.000 a\*` 5.003 de perl, la trigonome\*'trie e\*'tait faite par le module Math::Complex. A\*` partir de 5.004, le module Math::Trig (e\*'le\*'ment de la distribution standard de Perl) imple\*'mente les fonctions trigonome\*'triques. En interne, il utilise le module Math::Complex, et quelques fonctions peuvent s'e\*'chapper de l'axe des re\*'els vers le plan des complexes, comme par exemple le sinus inverse de 2. .PP Les arrondis dans des applications financie\*`res peuvent avoir des conse\*'quences majeures, et la me\*'thode utilise\*'e se doit d'e\*^tre spe\*'cifie\*'e pre\*'cise\*'ment. Dans ces cas, il vaut mieux ne pas avoir confiance dans un quelconque syste\*`me d'arrondis utilise\*' par Perl, mais imple\*'menter sa propre fonction d'arrondis telle qu'elle est ne\*'cessaire. .PP Pour comprendre pourquoi, remarquez comment il vous reste un proble\*`me lors d'une progression par cinq centie\*`mes\ : .PP .Vb 1 \& for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i} \& \& 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 \& 0.8 0.8 0.9 0.9 1.0 1.0 .Ve .PP Perl n'est pas en faute. C'est pareil qu'en C. L'\s-1IEEE\s0 dit que nous devons faire comme c\*,a. Les nombres en Perl dont la valeur absolue est un entier infe\*'rieur a\*` 2**31 (sur les machines 32 bit) fonctionneront globalement comme des entiers mathe\*'matiques. Les autres nombres ne sont pas garantis. .Sh "Comment faire des conversions nume\*'riques entre diffe\*'rentes bases, entre diffe\*'rentes repre\*'sentations\ ?" .IX Subsection "Comment faire des conversions nume'riques entre diffe'rentes bases, entre diffe'rentes repre'sentations?" Comme d'habitude avec Perl, il y a plusieurs moyens de le faire. Ci\-dessous, vous trouverez divers exemples d'approches permettant de faire les conversions courantes entre les repre\*'sentations des nombres. Ce n'est pas une liste exhaustive. .PP Certains exemples ci-dessous utilisent le module Bit::Vector du \&\s-1CPAN\s0. Les raisons du choix de Bit::Vector pluto\*^t que des fonctions pre\*'de\*'finies de perl sont qu'il sait traiter des nombres de n'importe quelle longueur, qu'il est optimise\*' pour certaines ope\*'rations et que sa notation semblera familie\*`re au moins a\*` certains programmeurs. .IP "Comment faire une conversion hexade\*'cimal vers de\*'cimal" 4 .IX Item "Comment faire une conversion hexade'cimal vers de'cimal" En utilisant la conversion interne de perl de la notation 0x\ : .Sp .Vb 1 \& $dec = 0xDEADBEEF; .Ve .Sp En utilisant la fonction hex\ : .Sp .Vb 1 \& $dec = hex("DEADBEEF"); .Ve .Sp En utilisant pack\ : .Sp .Vb 1 \& $dec = unpack("N", pack("H8", substr("0" x 8 . "DEADBEEF", \-8))); .Ve .Sp En utilisant le module Bit::Vector du \s-1CPAN\s0\ : .Sp .Vb 3 \& use Bit::Vector; \& $vec = Bit::Vector\->new_Hex(32, "DEADBEEF"); \& $dec = $vec\->to_Dec(); .Ve .IP "Comment faire une conversion de\*'cimal vers hexade\*'cimal" 4 .IX Item "Comment faire une conversion de'cimal vers hexade'cimal" En utilisant sprintf\ : .Sp .Vb 2 \& $hex = sprintf("%X", 3735928559); # majuscules A\-F \& $hex = sprintf("%x", 3735928559); # minuscules a\-f .Ve .Sp En utilisant unpack\ : .Sp .Vb 1 \& $hex = unpack("H*", pack("N", 3735928559)); .Ve .Sp En utilisant Bit::Vector\ : .Sp .Vb 3 \& use Bit::Vector; \& $vec = Bit::Vector\->new_Dec(32, \-559038737); \& $hex = $vec\->to_Hex(); .Ve .Sp En utilisant Bit::Vector qui accepte un nombre de bits impair\ : .Sp .Vb 4 \& use Bit::Vector; \& $vec = Bit::Vector\->new_Dec(33, 3735928559); \& $vec\->Resize(32); # suppression des 0 de remplissage \& $hex = $vec\->to_Hex(); .Ve .IP "Comment faire une conversion octal vers de\*'cimal" 4 .IX Item "Comment faire une conversion octal vers de'cimal" En utilisant la conversion interne de Perl des nombres pre\*'fixe\*'s par un ze\*'ro\ : .Sp .Vb 1 \& $dec = 033653337357; # notez le pre\*'fixe 0 ! .Ve .Sp En utilisant la fonction oct\ : .Sp .Vb 1 \& $dec = oct("33653337357"); .Ve .Sp En utilisant Bit::Vector: .Sp .Vb 4 \& use Bit::Vector; \& $vec = Bit::Vector\->new(32); \& $vec\->Chunk_List_Store(3, split(//, reverse "33653337357")); \& $dec = $vec\->to_Dec(); .Ve .IP "Comment faire une conversion de\*'cimal vers octal" 4 .IX Item "Comment faire une conversion de'cimal vers octal" En utilisant sprintf\ : .Sp .Vb 1 \& $oct = sprintf("%o", 3735928559); .Ve .Sp En utilisant Bit::Vector: .Sp .Vb 3 \& use Bit::Vector; \& $vec = Bit::Vector\->new_Dec(32, \-559038737); \& $oct = reverse join('', $vec\->Chunk_List_Read(3)); .Ve .IP "Comment faire une conversion binaire vers de\*'cimal" 4 .IX Item "Comment faire une conversion binaire vers de'cimal" Depuis Perl 5.6, vous pouvez e\*'crire les nombres binaires directement via la notation 0b\ : .Sp .Vb 1 \& $number = 0b10110110; .Ve .Sp En utilisant oct\ : .Sp .Vb 2 \& my $input = "10110110"; \& $decimal = oct( "0b$input" ); .Ve .Sp En utilisant pack et ord\ : .Sp .Vb 1 \& $decimal = ord(pack('B8', '10110110')); .Ve .Sp En utilisant pack et unpack pour les grands nombres\ : .Sp .Vb 3 \& $int = unpack("N", pack("B32", \& substr("0" x 32 . "11110101011011011111011101111", \-32))); \& $dec = sprintf("%d", $int); \& \& # substr() est utilise\*'e pour comple\*'ter le nombre par des ze\*'ros \& # a\*` gauche afin d'obtenir une chai\*^ne de 32 caracte\*`res .Ve .Sp En utilisant Bit::Vector\ : .Sp .Vb 2 \& $vec = Bit::Vector\->new_Bin(32, "11011110101011011011111011101111"); \& $dec = $vec\->to_Dec(); .Ve .IP "Comment faire une conversion de\*'cimal vers binaire" 4 .IX Item "Comment faire une conversion de'cimal vers binaire" En utilisant sprintf (perl 5.6 et plus)\ : .Sp .Vb 1 \& $bin = sprintf("%b", 3735928559); .Ve .Sp En utilisant unpack\ : .Sp .Vb 1 \& $bin = unpack("B*", pack("N", 3735928559)); .Ve .Sp En utilisant Bit::Vector\ : .Sp .Vb 3 \& use Bit::Vector; \& $vec = Bit::Vector\->new_Dec(32, \-559038737); \& $bin = $vec\->to_Bin(); .Ve .Sp Les autres conversions (par exemple hex \-> oct, bin \-> hex, etc.) sont laisse\*'es en exercices au lecteur. .Sh "Pourquoi & ne fonctionne-t-il pas comme je le veux\ ?" .IX Subsection "Pourquoi & ne fonctionne-t-il pas comme je le veux?" Le comportement des ope\*'rateurs arithme\*'tiques binaires varie selon qu'ils sont utilise\*'s sur des nombres ou des chai\*^nes. Ces ope\*'rateurs traitent une chai\*^ne comme une se\*'rie de bits et travaillent avec (la chai\*^ne \f(CW"3"\fR est le motif de bits \f(CW00110011\fR). Ces ope\*'rateurs travaillent avec la forme binaire d'un nombre (le nombre \f(CW3\fR est traite\*' comme le motif de bits \f(CW00000011\fR). .PP Le fait de dire \f(CW\*(C`11 & 3\*(C'\fR effectue donc l'ope\*'ration \*(L"et\*(R" bit\-a\*`\-bit sur des nombres (donnant ici \f(CW3\fR). Le fait de dire \f(CW"11" & "3"\fR effectue un \*(L"et\*(R" bit\-a\*`\-bit sur des chai\*^nes (donnant \f(CW"1"\fR). .PP La plupart des proble\*`mes pose\*'s par \f(CW\*(C`&\*(C'\fR et \f(CW\*(C`|\*(C'\fR surviennent parce que le programmeur pense qu'il traite un nombre alors qu'en fait c'est une chai\*^ne. Les autres proble\*`mes se posent parce que le programmeur dit\ : .PP .Vb 3 \& if ("\e020\e020" & "\e101\e101") { \& # ... \& } .Ve .PP mais une chai\*^ne constitue\*'e de deux octets nuls (le re\*'sultat de \&\f(CW"\e020\e020" & "\e101\e101"\fR) n'est pas une valeur fausse en Perl. Vous avez besoin d'e\*'crire\ : .PP .Vb 3 \& if ( ("\e020\e020" & "\e101\e101") !~ /[^\e000]/) { \& # ... \& } .Ve .Sh "Comment multiplier des matrices\ ?" .IX Subsection "Comment multiplier des matrices?" Utiliser les modules Math::Matrix ou Math::MatrixReal (disponibles sur le \s-1CPAN\s0) ou l'extension \s-1PDL\s0 (e\*'galement disponible sur le \s-1CPAN\s0). .Sh "Comment effectuer une ope\*'ration sur une se\*'rie d'entiers\ ?" .IX Subsection "Comment effectuer une ope'ration sur une se'rie d'entiers?" Pour appeler une fonction sur chaque e\*'le\*'ment d'un tableau, et re\*'cupe\*'rer le re\*'sultat, utiliser\ : .PP .Vb 1 \& @results = map { my_func($_) } @array; .Ve .PP Par exemple\ : .PP .Vb 1 \& @triple = map { 3 * $_ } @single; .Ve .PP Pour appeler une fonction sur chaque e\*'le\*'ment d'un tableau, mais sans tenir compte du re\*'sultat\ : .PP .Vb 3 \& foreach $iterator (@array) { \& some_func($iterator); \& } .Ve .PP Pour appeler une fonction sur chaque entier d'un (petit) intervalle, on \&\fBpeut\fR utiliser\ : .PP .Vb 1 \& @results = map { some_func($_) } (5 .. 25); .Ve .PP mais il faut e\*^tre conscient que l'ope\*'rateur \f(CW\*(C`..\*(C'\fR cre\*'e un tableau de tous les entiers de l'intervalle utilisant beaucoup de me\*'moire pour de grands intervalles. Il vaut mieux utiliser\ : .PP .Vb 4 \& @results = (); \& for ($i=5; $i < 500_005; $i++) { \& push(@results, some_func($i)); \& } .Ve .PP Cette situation a e\*'te\*' corrige\*'e dans Perl5.005. L'usage de \f(CW\*(C`..\*(C'\fR dans une boucle \f(CW\*(C`for\*(C'\fR ite\*'rera sur l'intervalle, sans cre\*'er tout l'intervalle. .PP .Vb 3 \& for my $i (5 .. 500_005) { \& push(@results, some_func($i)); \& } .Ve .PP ne cre\*'era pas une liste de 500\ 000 entiers. .Sh "Comment produire des chiffres romains\ ?" .IX Subsection "Comment produire des chiffres romains?" Re\*'cupe\*'rez et utilisez le module . .Sh "Pourquoi mes nombres ale\*'atoires ne sont-ils pas ale\*'atoires\ ?" .IX Subsection "Pourquoi mes nombres ale'atoires ne sont-ils pas ale'atoires?" Si vous utilisez une version de Perl ante\*'rieure a\*` la 5.004, vous devez appeler \f(CW\*(C`srand\*(C'\fR une fois au de\*'but de votre programme pour ensemencer le ge\*'ne\*'rateur de nombres ale\*'atoires. .PP .Vb 1 \& BEGIN { srand() if $] < 5.004 } .Ve .PP Les versions 5.004 et supe\*'rieures appellent automatiquement \f(CW\*(C`srand\*(C'\fR de\*`s le de\*'but. N'appelez pas \f(CW\*(C`srand\*(C'\fR plus d'une fois \*(-- vous rendriez vos nombres moins ale\*'atoires, pluto\*^t que l'inverse. .PP Les ordinateurs sont doue\*'s pour e\*^tre de\*'terministes et mauvais lorsqu'il s'agit d'e\*^tre ale\*'atoires (malgre\*' les apparences provoque\*'es par les bogues dans vos programmes\ :\-). Lisez l'article \fIrandom\fR par Tom Phoenix dans la collection \*(L"Far More Than You Ever Wanted To Know\*(R" sur pour en savoir plus a\*` ce sujet. John von Neumann disait\ : X\ Quiconque tente de produire des nombres ale\*'atoires par des moyens de\*'terministes vit dans le pe\*'che\*'.\ X .PP Si vous de\*'sirez des nombres qui soient plus ale\*'atoires que ce que fournit \f(CW\*(C`rand\*(C'\fR avec \f(CW\*(C`srand\*(C'\fR, jetez aussi un oeil au module Math::TrulyRandom sur le \s-1CPAN\s0. Il utilise des imperfections de l'horloge du syste\*`me pour ge\*'ne\*'rer des nombres ale\*'atoires, mais ceci prend un certain temps. Si vous voulez un meilleur ge\*'ne\*'rateur pseudo\-ale\*'atoire que celui qui vient avec le syste\*`me d'exploitation, lisez les X\ Numerical Recipes in C\ X sur . .Sh "Comment obtenir un nombre ale\*'atoire entre X et Y\ ?" .IX Subsection "Comment obtenir un nombre ale'atoire entre X et Y?" \&\f(CW\*(C`rand($x)\*(C'\fR retourne un nombre tel que \f(CW\*(C`0 <= rand($x) < $x\*(C'\fR. Donc perl peut ge\*'ne\*'rer un nombre ale\*'atoire entre 0 et la valeur qui se\*'pare \&\fIX\fR et \fIY\fR. .PP Et donc, pour obtenir un entier entre 10 et 15 inclus, vous pouvez ge\*'ne\*'rer un nombre entre 0 et 5 auquel vous ajouterez 10. .PP .Vb 1 \& my $nombre = 10 + int rand( 15\-10+1 ); .Ve .PP Ensuite, on peut transformer ce calcul pour en faire une fonction ge\*'ne\*'rique. Elle choisit un nombre ale\*'atoire entre deux entiers donne\*'s\ : .PP .Vb 7 \& sub random_int_in ($$) { \& my($min, $max) = @_; \& # On suppose que les deux arguments sont eux\-me\*^mes des entiers ! \& return $min if $min == $max; \& ($min, $max) = ($max, $min) if $min > $max; \& return $min + int rand(1 + $max \- $min); \& } .Ve .SH "Donne\*'es\ : dates" .IX Header "Donne'es: dates" .Sh "Comment trouver le jour ou la semaine de l'anne\*'e\ ?" .IX Subsection "Comment trouver le jour ou la semaine de l'anne'e?" La fonction \fIlocaltime()\fR retourne le jour de l'anne\*'e. Appeler sans argument, localtime se base sur l'heure (et la date) courante. .PP .Vb 1 \& $jour_de_l_annee = (localtime)[7]; .Ve .PP Le module \s-1POSIX\s0 propose le jour ou la semaine de l'anne\*'e dans les formats disponible : .PP .Vb 3 \& use POSIX qw/strftime/; \& my $jour_de_l_annee = strftime "%j", localtime; \& my $semaine_de_l_annee = strftime "%W", localtime; .Ve .PP Pour obtenir le jour de l'anne\*'e d'une date quelconque, utilisez le module Time::Local pour obtenir un temps en secondes depuis l'origine des temps que vous fournirez comme argument a\*` localtime. .PP .Vb 4 \& use POSIX qw/strftime/; \& use Time::Local; \& my $semaine_de_l_annee = strftime "%W", \& localtime( timelocal( 0, 0, 0, 18, 11, 1987 ) ); .Ve .PP Le module Date::Calc propose deux fonctions pour calculer cela\ : .PP .Vb 3 \& use Date::Calc; \& my $jour_de_l_annee = Day_of_Year( 1987, 12, 18 ); \& my $semaine_de_l_annee = Week_of_Year( 1987, 12, 18 ); .Ve .Sh "Comment trouver le sie\*`cle ou le mille\*'naire actuel\ ?" .IX Subsection "Comment trouver le sie`cle ou le mille'naire actuel?" Utilisez les fonctions simples suivantes\ : .PP .Vb 3 \& sub trouve_siecle { \& return int((((localtime(shift || time))[5] + 1999))/100); \& } \& \& sub trouve_millenaire { \& return 1+int((((localtime(shift || time))[5] + 1899))/1000); \& } .Ve .PP Sur certains syste\*`mes, la fonction \fIstrftime()\fR du module \s-1POSIX\s0 a e\*'te\*' e\*'tendue d'une fac\*,on non standard pour utiliser le format \f(CW%C\fR, et ils pre\*'tendent que cela repre\*'sente le \*(L"sie\*`cle\*(R". Ce n'est pas le cas, puisque sur la plupart de ces syste\*`mes, cela ne repre\*'sente que les deux premiers chiffres de l'anne\*'e a\*` quatre chiffres, et ne peut ainsi pas e\*^tre utilise\*' pour de\*'terminer de fac\*,on fiable le sie\*`cle ou le mille\*'naire courant. .Sh "Comment comparer deux dates ou en calculer la diffe\*'rence\ ?" .IX Subsection "Comment comparer deux dates ou en calculer la diffe'rence?" (contribution de brian d foy) .PP Vous pouvez tout simplement stocker vos dates sous formes de nombres et les soustraire. Mais les choses ne sont pas toujours aussi simples. Si vous souhaitez utiliser des dates mises en forme, les modules Date::Manip, Date::Calc ou DateTime devraient vous aider. .Sh "Comment convertir une chai\*^ne de caracte\*`res en secondes depuis l'origine des temps\ ?" .IX Subsection "Comment convertir une chai^ne de caracte`res en secondes depuis l'origine des temps?" Si cette chai\*^ne est suffisamment re\*'gulie\*`re pour avoir toujours le me\*^me format, on peut la de\*'couper et en passer les morceaux a\*` la fonction \&\f(CW\*(C`timelocal\*(C'\fR du module standard Time::Local. Autrement, regarder les modules Date::Calc et Date::Manip disponibles sur le \s-1CPAN\s0. .Sh "Comment trouver le jour du calendrier Julien\ ?" .IX Subsection "Comment trouver le jour du calendrier Julien?" (contribution de brian d foy et de Dave Cross) .PP Vous pouvez utiliser le module Time::JulianDay disponible sur le \&\s-1CPAN\s0. Assurez-vous tout de me\*^me que c'est bien le jour \fIJulien\fR que vous voulez. Chacun ayant son ide\*'e sur les jours Julien, regardez pour en savoir plus. .PP Vous pouvez aussi essayer le module DateTime qui sait convertir une date ou une heure en un jour Julien. .PP .Vb 2 \& $ perl \-MDateTime \-le'print DateTime\->today\->jd' \& 2453401.5 .Ve .PP Ou le jour Julien modifie\*' .PP .Vb 2 \& $ perl \-MDateTime \-le'print DateTime\->today\->mjd' \& 53401 .Ve .PP Ou me\*^me le jour de l'anne\*'e (que certains croient e\*^tre le jour Julien) .PP .Vb 2 \& $ perl \-MDateTime \-le'print DateTime\->today\->doy' \& 31 .Ve .Sh "Comment trouver la date d'hier\ ?" .IX Subsection "Comment trouver la date d'hier?" (contribution de brian d foy) .PP Utilisez l'un des modules Date. Le module \f(CW\*(C`DateTime\*(C'\fR fait cela simplement et vous donne le me\*^me moment (me\*^me heure) mais hier. .PP .Vb 1 \& use DateTime; \& \& my $hier = DateTime\->now\->subtract( days => 1 ); \& \& print "Hier e\*'tait $hier\en"; .Ve .PP Vous pouvez aussi choisir le module \f(CW\*(C`Date::Calc\*(C'\fR en utilisant sa fonction Today_and_Now. .PP .Vb 1 \& use Date::Calc qw( Today_and_Now Add_Delta_DHMS ); \& \& my @hier = Add_Delta_DHMS( Today_and_Now(), \-1, 0, 0, 0 ); \& \& print "@hier\en"; .Ve .PP De nombreuses personnes essaient d'utiliser le temps pluto\*^t que le calendrier pour ge\*'rer les dates en supposant que tous les jours ont une dure\*'e de vingt quatre heures. Or pour de nombreuses personnes, ils existent deux jours par an ou\*` ce n'est pas vrai\ : les jours de changement d'heure (l'heure d'e\*'te\*' et l'heure d'hiver). Laissez donc les modules faire ce boulot. .Sh "Perl a\-t-il un proble\*`me avec l'an 2000\ ? Perl est-il compatible an 2000\ ?" .IX Subsection "Perl a-t-il un proble`me avec l'an 2000? Perl est-il compatible an 2000?" Re\*'ponse courte\ : Non, Perl n'a pas de proble\*`me avec l'an 2000. Oui, Perl est compatible an 2000 (si ceci veut dire quelque chose). Toutefois, les programmeurs que vous avez embauche\*'s pour l'utiliser ne le sont probablement pas. .PP Re\*'ponse longue\ : la question demande une vraie compre\*'hension du proble\*`me. Perl est juste tout aussi compatible an 2000 que votre crayon \*(-- ni plus ni moins. Pouvez-vous utilisez votre crayon pour re\*'diger un me\*'mo non compatible an 2000\ ? Bien su\*^r que oui. Est-ce la faute du crayon\ ? Bien su\*^r que non. .PP Les fonctions de date et d'heure fournies avec Perl (gmtime et localtime) donnent des informations ade\*'quates pour de\*'terminer l'anne\*'e bien au\-dela\*` de l'an 2000 (2038 marque le de\*'but des proble\*`mes pour les machines 32\-bits). L'anne\*'e renvoye\*'e par ces fonctions lorsqu'elles sont utilise\*'es dans un contexte de liste est l'anne\*'e, moins 1900. Pour les anne\*'es entre 1910 et 1999 ceci est un nombre a\*` deux chiffres \fIpar hasard\fR. Pour e\*'viter le proble\*`me de l'an 2000, ne traitez tout simplement pas l'anne\*'e comme un nombre a\*` deux chiffres. Elle ne l'est pas. .PP Quand \fIgmtime()\fR et \fIlocaltime()\fR sont utilise\*'es dans un contexte scalaire, elles renvoient une chai\*^ne qui contient l'anne\*'e e\*'crite en entier. Par exemple, \f(CW\*(C`$timestamp = gmtime(1005613200)\*(C'\fR fixe \&\f(CW$timestamp\fR a\*` la valeur \*(L"Tue Nov 13 01:00:00 2001\*(R". Ici encore, il n'y a pas de proble\*`me de l'an 2000. .PP Ceci ne veut pas dire que Perl ne peut pas e\*^tre utilise\*' pour cre\*'er des programmes qui ne respecteront pas l'an 2000. Il peut l'e\*^tre. Mais un crayon le peut aussi. La faute en revient a\*` l'utilisateur, pas au langage. Au risque d'indisposer la \s-1NRA\s0 (National Rifle Association)\ : X\ Perl ne viole pas l'an 2000, les gens le font\ X. Pour un expose\*' plus complet, voir . .SH "Donne\*'es\ : chai\*^nes de caracte\*`res" .IX Header "Donne'es: chai^nes de caracte`res" .Sh "Comment m'assurer de la validite\*' d'une entre\*'e\ ?" .IX Subsection "Comment m'assurer de la validite' d'une entre'e?" (contribution de brian d foy) .PP Il existe plusieurs moyens de ve\*'rifier que les valeurs sont bien celles que vous attendez ou que vous acceptez. En plus des exemples spe\*'cifiques que vous trouverez dans la \s-1FAQ\s0 perl, vous pouvez aussi jeter un oeil aux modules dont le nom contient \*(L"Assert\*(R" ou \*(L"Validate\*(R" ainsi que d'autres modules comme \f(CW\*(C`Regexp::Common\*(C'\fR. .PP Quelques modules savent valider des types particuliers d'entre\*'es. Par exemple \f(CW\*(C`Business::ISBN\*(C'\fR, \f(CW\*(C`Business::CreditCard\*(C'\fR, \f(CW\*(C`Email::Valid\*(C'\fR et \&\f(CW\*(C`Data::Validate::IP\*(C'\fR. .Sh "Comment supprimer les caracte\*`res d'e\*'chappement d'une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment supprimer les caracte`res d'e'chappement d'une chai^ne de caracte`res?" Cela de\*'pend de que vous entendez par \*(L"caracte\*`re d'e\*'chappement\*(R". Les caracte\*`res d'e\*'chappement d'\s-1URL\s0 sont traite\*'s dans . Les caracte\*`res de l'interpre\*'teur de commandes avec des barres obliques inverse\*'es (\f(CW\*(C`\e\*(C'\fR) sont supprime\*'s par\ : .PP .Vb 1 \& s/\e\e(.)/$1/g; .Ve .PP Ceci ne convertira pas les \f(CW"\en"\fR ou \f(CW"\et"\fR ni aucun autre caracte\*`re spe\*'cial. .Sh "Comment enlever des paires de caracte\*`res successifs\ ?" .IX Subsection "Comment enlever des paires de caracte`res successifs?" (contribution de brian d foy) .PP Vous pouvez utiliser l'ope\*'rateur de substitution pour trouver des couples de caracte\*`res identiques et les remplacer pour un seul caracte\*`re. Dans cette substitution, nous cherchons un caracte\*`re \&\f(CW\*(C`(.)\*(C'\fR. Les parenthe\*`ses de me\*'morisation stockent le caracte\*`re reconnu dans la re\*'fe\*'rence \f(CW\*(C`\e1\*(C'\fR que nous utilisons imme\*'diatement pour reconnai\*^tre le me\*^me caracte\*`re une seconde fois. Nous remplac\*,ons ensuite ce couple de caracte\*`res par le caracte\*`re \f(CW$1\fR (qui est l'e\*'quivalent de \f(CW\*(C`\e1\*(C'\fR mais dans la chai\*^ne de remplacement). .PP .Vb 1 \& s/(.)\e1/$1/g; .Ve .PP On peut aussi utiliser l'ope\*'rateur de translitte\*'ration, \f(CW\*(C`tr///\*(C'\fR. Dans cet exemple, la liste de recherche est vide mais nous ajoutons le modificateur \f(CW\*(C`c\*(C'\fR pour utiliser en fait le comple\*'mentaire de cette liste, c'est a\*` dire tout. La liste de remplacement, elle aussi, ne contient rien et donc la translitte\*'ration est une ope\*'ration vide puisque nous n'effectuons aucun remplacement (ou plus exactement, nous remplac\*,ons chaque caracte\*`re par lui\-me\*^me). Par contre, comme nous avons ajouter le modificateur \f(CW\*(C`s\*(C'\fR, les caracte\*`res conse\*'cutifs identiques sont remplace\*'s par une seule occurrence. .PP .Vb 2 \& my $str = 'Haarlem'; # aux Pays\-bas \& $str =~ tr//cs; # Harlem, comme a\*` New\-York .Ve .Sh "Comment effectuer des appels de fonction dans une chai\*^ne\ ?" .IX Subsection "Comment effectuer des appels de fonction dans une chai^ne?" (contribution de brian d foy) .PP Ceci est documente\*' dans perlref et, bien que ce ne soit pas la chose la plus facile a\*` lire, c\*,a marche. Dans chacun des exemples suivants, nous appelons la fonction a\*` l'inte\*'rieur des accolades en utilisant le de\*'re\*'fe\*'rencement d'une re\*'fe\*'rence. Si nous avons plus d'un seul re\*'sultat, nous pouvons construire et de\*'re\*'fencer un tableau anonyme. Dans ce cas, nous appelons la fonction dans un contexte de liste\ : .PP .Vb 1 \& print "The time values are @{ [localtime] }.\en"; .Ve .PP Si nous voulons appeler la fonction dans un contexte scalaire, il nous faut faire un petit effort. Il est possible de placer n'importe quel code entre les accolades donc il suffit de placer un code qui retourne une re\*'fe\*'rence a\*` un scalaire\ : .PP .Vb 1 \& print "La date est ${\e(scalar localtime)}.\en" \& \& print "La date est ${ my $x = localtime; \e$x }.\en"; .Ve .PP Si votre fonction retourne de\*'ja\*` une re\*'fe\*'rence, vous n'avez pas besoin de la construire vous\-me\*^me : .PP .Vb 1 \& sub timestamp { my $t = localtime; \e$t } \& \& print "La date est ${ timestamp() }.\en"; .Ve .PP Le module \f(CW\*(C`Interpolation\*(C'\fR peut aussi faire un peu de magie pour vous. Vous pouvez spe\*'cifier un nom, dans notre cas \f(CW\*(C`E\*(C'\fR, lie\*'e a\*` une table de hachage qui fera l'interpolation pour vous. Il y a encore plusieurs autres moyens de faire cela. .PP .Vb 2 \& use Interpolation E => 'eval'; \& print "The time values are $E{localtime()}.\en"; .Ve .PP Dans la plupart des cas, il est probablement plus simple d'utiliser la concate\*'nation de chai\*^ne qui impose un contexte scalaire\ : .PP .Vb 1 \& print "La date est " . localtime . ".\en"; .Ve .Sh "Comment repe\*'rer des e\*'le\*'ments apparie\*'s ou imbrique\*'s\ ?" .IX Subsection "Comment repe'rer des e'le'ments apparie's ou imbrique's?" Ceci ne peut e\*^tre re\*'alise\*' en une seule expression re\*'gulie\*`re, me\*^me tre\*`s complique\*'e. Pour trouver quelque chose se situant entre deux caracte\*`res simples, un motif comme \f(CW\*(C`/x([^x]*)x/\*(C'\fR mettra les morceaux de l'intervalle dans \f(CW$1\fR. Lorsque le se\*'parateur est de plusieurs caracte\*`res, il faudrait en utiliser un ressemblant plus a\*` \&\f(CW\*(C`/alpha(.*?)omega/\*(C'\fR. Mais aucun de des deux ne ge\*`re les motifs imbrique\*'s. Pour les expressions imbrique\*'es utilisant \f(CW\*(C`(\*(C'\fR, \f(CW\*(C`{\*(C'\fR, C([} ou \f(CW\*(C`<\*(C'\fR comme de\*'limiteurs, utilisez le module \s-1CPAN\s0 Regexp::Common ou voyez "\*(L"(??{ code })\*(R" in perlre. Pour les autres cas, il vous faudra e\*'crire un analyseur. .PP Si vous songez se\*'rieusement a\*` e\*'crire un analyseur syntaxique, de nombreux modules ou gadgets pourront vous rendre la vie plus facile. Il y a les modules du \s-1CPAN\s0 Parse::RecDescent, Parse::Yapp et Text::Balanced ainsi que le programme byacc. Depuis perl 5.8, Text::Balanced fait partie de la distribution standard. .PP Une approche simple, mais destructive, consiste a\*` partir de l'inte\*'rieur pour aller vers l'exte\*'rieur en retirant les plus petites parties imbrique\*'es les unes apre\*`s les autres\ : .PP .Vb 3 \& while (s/BEGIN((?:(?!BEGIN)(?!END).)*)END//gs) { \& # faire quelque chose de $1 \& } .Ve .PP Une approche plus complexe et contorsionne\*'e est de faire faire le travail par le moteur d'expressions rationnelles de Perl. Ce qui suit est une courtoisie de Dean Inada, et a pluto\*^t l'allure d'une entre\*'e de l'Obfuscated Perl Contest, mais ce code fonctionne vraiment\ : .PP .Vb 3 \& # $_ contient la chai\*^ne a\*` analyser \& # BEGIN et END sont les marqueurs ouvrant et fermants pour le \& # texte inclus. \& \& @( = ('(',''); \& @) = (')',''); \& ($re=$_)=~s/((BEGIN)|(END)|.)/$)[!$3]\eQ$1\eE$([!$2]/gs; \& @$ = (eval{/$re/},$@!~/unmatched/i); \& print join("\en",@$[0..$#$]) if( $$[\-1] ); .Ve .Sh "Comment inverser une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment inverser une chai^ne de caracte`res?" Utiliser \fIreverse()\fR dans un contexte scalaire, tel qu'indique\*' dans \*(L"reverse\*(R" in perlfunc. .PP .Vb 1 \& $reversed = reverse $string; .Ve .Sh "Comment de\*'velopper les tabulations dans une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment de'velopper les tabulations dans une chai^ne de caracte`res?" On peut le faire soi\-me\*^me\ : .PP .Vb 1 \& 1 while $string =~ s/\et+/' ' x (length($&) * 8 \- length($`) % 8)/e; .Ve .PP Ou utiliser simplement le module Text::Tabs (qui fait partie de la distribution standard de Perl). .PP .Vb 2 \& use Text::Tabs; \& @expanded_lines = expand(@lines_with_tabs); .Ve .Sh "Comment remettre en forme un paragraphe\ ?" .IX Subsection "Comment remettre en forme un paragraphe?" Utiliser Text::Warp (qui fait partie de la distribution standard de Perl)\ : .PP .Vb 2 \& use Text::Wrap; \& print wrap("\et", ' ', @paragraphs); .Ve .PP Les paragraphes passe\*'s en argument a\*` Text::Warp ne doivent pas contenir de caracte\*`re de saut de ligne. Text::Wrap ne justifie pas les lignes (aligne\*'es a\*` droite). .PP Ou utilisez le module \s-1CPAN\s0 Text::Autoformat. Les formatage de fichiers s'effectue aise\*'ment via un alias shell comme\ : .PP .Vb 2 \& alias fmt="perl \-i \-MText::Autoformat \-n0777 \e \& \-e 'print autoformat $_, {all=>1}' $*" .Ve .PP Voir la documentation de Text::Autoformat pour connai\*^tre toutes ses possibilite\*'s. .Sh "Comment acce\*'der a\*` ou modifier N caracte\*`res d'une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment acce'der a` ou modifier N caracte`res d'une chai^ne de caracte`res?" Vous pouvez acce\*'der aux premiers caracte\*`res d'une chai\*^ne via \&\fIsubstr()\fR. Pour obtenir le premier caracte\*`re, par exemple, commencer a\*` la position 0 et re\*'cupe\*'rer une sous\-chai\*^ne de longueur 1. .PP .Vb 2 \& $string = "Just another Perl Hacker"; \& $first_char = substr( $string, 0, 1 ); # 'J' .Ve .PP Pour modifier une partie d'une chai\*^ne, vous pouvez utiliser le quatrie\*`me argument optionnel qui est la chai\*^ne de remplacement. .PP .Vb 1 \& substr( $string, 13, 4, "Perl 5.8.0" ); .Ve .PP Vous pouvez aussi utiliser \fIsubstr()\fR en tant que lvalue\ : .PP .Vb 1 \& substr($a, 0, 3) = "Tom"; .Ve .Sh "Comment changer la nie\*`me occurrence de quelque chose\ ?" .IX Subsection "Comment changer la nie`me occurrence de quelque chose?" Il faut conserver soi\-me\*^me l'e\*'volution de n. Par exemple, si l'on souhaite changer la cinquie\*`me occurrence de \f(CW"whoever"\fR ou \&\f(CW"whomever"\fR en \f(CW"whosoever"\fR ou \f(CW"whomsoever"\fR, sans tenir compte de la casse. Supposons dans la suite que \f(CW$_\fR contienne la chai\*^ne a\*` modifier. .PP .Vb 6 \& $count = 0; \& s{((whom?)ever)}{ \& ++$count == 5 # Est\-ce la cinquie\*`me ? \& ? "${2}soever" # oui: faire l'e\*'change \& : $1 # non: le laisser tel quel \& }ige; .Ve .PP Dans des cas plus ge\*'ne\*'raux, on peut utiliser le modificateur \f(CW\*(C`/g\*(C'\fR dans une boucle \f(CW\*(C`while\*(C'\fR, en comptant le nombre de correspondances. .PP .Vb 8 \& $WANT = 3; \& $count = 0; \& $_ = "One fish two fish red fish blue fish"; \& while (/(\ew+)\es+fish\eb/gi) { \& if (++$count == $WANT) { \& print "The third fish is a $1 one.\en"; \& } \& } .Ve .PP Ceci sort: \f(CW"The third fish is a red one."\fR On peut aussi utiliser un compteur de re\*'pe\*'tition, et un motif re\*'pe\*'te\*' comme ceci\ : .PP .Vb 1 \& /(?:\ew+\es+fish\es+){2}(\ew+)\es+fish/i; .Ve .Sh "Comment compter le nombre d'occurrences d'une sous\-chai\*^ne dans une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment compter le nombre d'occurrences d'une sous-chai^ne dans une chai^ne de caracte`res?" Plusieurs moyens sont possibles, avec une efficacite\*' variable. Pour trouver le nombre d'un caracte\*`re particulier (X) dans une chai\*^ne, on peut utiliser la fonction \f(CW\*(C`tr///\*(C'\fR comme ceci\ : .PP .Vb 3 \& $string = "ThisXlineXhasXsomeXx'sXinXit"; \& $count = ($string =~ tr/X//); \& print "There are $count X characters in the string"; .Ve .PP Ceci marche bien lorsque l'on cherche un seul caracte\*`re. Cependant si l'on essaye de compter des sous\-chai\*^nes de plusieurs caracte\*`res a\*` l'inte\*'rieur d'une chai\*^ne plus grande, \f(CW\*(C`tr///\*(C'\fR ne marchera pas. On peut alors envelopper d'une boucle \fIwhile()\fR une recherche de motif globale. Par exemple, comptons les entiers ne\*'gatifs\ : .PP .Vb 3 \& $string = "\-9 55 48 \-2 23 \-76 4 14 \-44"; \& while ($string =~ /\-\ed+/g) { $count++ } \& print "There are $count negative numbers in the string"; .Ve .PP Une autre manie\*`re de faire utilise la reconnaissance globale dans un contexte de liste puis assigne le re\*'sultat a\*` un scalaire, produisant ainsi le nombre de reconnaissances. .PP .Vb 1 \& $count = () = $string =~ /\-\ed+/g; .Ve .Sh "Comment mettre en majuscule toutes les premie\*`res lettre des mots d'une ligne\ ?" .IX Subsection "Comment mettre en majuscule toutes les premie`res lettre des mots d'une ligne?" Pour mettre en lettres majuscules toutes les premie\*`res lettres des mots\ : .PP .Vb 1 \& $line =~ s/\eb(\ew)/\eU$1/g; .Ve .PP Ceci a pour effet de bord de transformer "\f(CW\*(C`aujourd'hui\*(C'\fR\*(L" en \&\*(R"\f(CW\*(C`Aujourd'Hui\*(C'\fR". C'est parfois ce qu'on veut. Sinon, on peut pre\*'fe\*'rer cette solution (sugge\*'re\*'e par brian d foy)\ : .PP .Vb 7 \& $string =~ s/ ( \& (^\ew) #au de\*'but d'une ligne \& | # ou \& (\es\ew) #pre\*'ce\*'de\*' d'un espace \& ) \& /\eU$1/xg; \& $string =~ /([\ew']+)/\eu\eL$1/g; .Ve .PP Pour transformer toute la ligne en lettres majuscules\ : .PP .Vb 1 \& $line = uc($line); .Ve .PP A\*` l'inverse, pour avoir chaque mot en lettres minuscules, avec la premie\*`re lettre majuscule\ : .PP .Vb 1 \& $line =~ s/(\ew+)/\eu\eL$1/g; .Ve .PP On peut (et l'on devrait toujours) rendre ces caracte\*`res sensibles aux locales en plac\*,ant une directive \f(CW\*(C`use locale\*(C'\fR dans le programme. Voir perllocale pour d'interminables de\*'tails sur les locales. .PP On s'y re\*'fe\*`re parfois comme consistant a\*` mettre quelque chose en \&\*(L"casse de titre\*(R", mais ce n'est pas tout a\*` fait juste. Observez la capitalisation correcte du film \fIDr. Strangelove or\ : How I Learned to Stop Worrying and Love the Bomb\fR, par exemple. (NdT\ : d'autant que l'usage en franc\*,ais est de ne mettre de majuscule qu'en de\*'but de phrase et aux noms propres.) .PP Le module Text::Autoformat de Domian Conway fournit quelques transformations sympathiques\ : .PP .Vb 3 \& use Text::Autoformat; \& my $x = "Dr. Strangelove or: How I Learned to Stop ". \& "Worrying and Love the Bomb"; \& \& print $x, "\en"; \& for my $style (qw( sentence title highlight )) \& { \& print autoformat($x, { case => $style }), "\en"; \& } .Ve .Sh "Comment de\*'couper une chai\*^ne se\*'pare\*'e par un [caracte\*`re] sauf a\*` l'inte\*'rieur d'un [caracte\*`re]\ ?" .IX Subsection "Comment de'couper une chai^ne se'pare'e par un [caracte`re] sauf a` l'inte'rieur d'un [caracte`re]?" Plusieurs modules savent ge\*'rer ce genre d'analyses \*(-- Text::Balanced, Text::CSV, Text::CSV_XS et Text::ParseWord parmi d'autres. .PP Prenons l'exemple du cas ou\*` l'on souhaite de\*'couper une chai\*^ne qui est subdivise\*'e en diffe\*'rents champs par des virgules. On ne peut utiliser \&\f(CW\*(C`split(/,/)\*(C'\fR parce qu'il ne faudrait pas de\*'couper si la virgule est entre guillemets. Par exemple pour la ligne de donne\*'e suivante\ : .PP .Vb 1 \& SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped" .Ve .PP A\*` cause de la restriction impose\*'e par les guillemets, ceci devient un proble\*`me relativement complexe. Heureusement, nous avons Jeffrey Frield, auteur du livre \fIMastering Regular Expressions\fR, qui s'est penche\*' sur le proble\*`me pour nous. Il sugge\*`re (en supposant que \f(CW$text\fR contient la chai\*^ne)\ : .PP .Vb 7 \& @new = (); \& push(@new, $+) while $text =~ m{ \& "([^\e"\e\e]*(?:\e\e.[^\e"\e\e]*)*)",? # regroupe les e\*'le\*'ments entre guillemets \& | ([^,]+),? \& | , \& }gx; \& push(@new, undef) if substr($text,\-1,1) eq ','; .Ve .PP Pour repre\*'senter un vrai guillemet a\*` l'inte\*'rieur d'un champ de\*'limite\*' par des guillemets, il faut le prote\*'ger d'une barre oblique inverse comme caracte\*`re d'e\*'chappement (c.\-a\*`\-d. \f(CW"comme \e"ceci\e""\fR). .PP Comme autre choix, le module Text::ParseWords (qui fait partie de la distribution standard de Perl) permet de faire\ : .PP .Vb 2 \& use Text::ParseWords; \& @new = quotewords(",", 0, $text); .Ve .PP Il existe aussi un module Text::CSV (Comma\-Separated Values \*(-- Valeurs se\*'pare\*'es par des virgules) sur le \s-1CPAN\s0. .Sh "Comment supprimer des espaces blancs au de\*'but/a\*` la fin d'une chai\*^ne\ ?" .IX Subsection "Comment supprimer des espaces blancs au de'but/a` la fin d'une chai^ne?" (contribution de brian d foy) .PP Une substitution peut le faire pour vous. Pour une simple ligne, vous voulez remplacer tous les espaces en de\*'but et en fin de ligne par rien du tout. Cette double substitution le fait : .PP .Vb 2 \& s/^\es+//; \& s/\es+$//; .Ve .PP Vous pourriez aussi l'e\*'crire en une seule substitution bien que ce soit plus lent. Mais ce n'est peut\-e\*^tre pas important pour vous. .PP .Vb 1 \& s/^\es+|\es+$//g; .Ve .PP Dans cette expression rationnelle, l'alternative est reconnue soit en de\*'but soit en fin de chai\*^ne puisque les ancres ont une pre\*'ce\*'dence plus faible que l'alternative. Avec le modificateur \f(CW\*(C`/g\*(C'\fR, la substitution s'effectue partout ou\*` elle est reconnue, et donc au de\*'but et a\*` la fin. Souvenez-vous que \f(CW\*(C`\es+\*(C'\fR reconnai\*^t les caracte\*`res de fin de ligne et que \f(CW\*(C`$\*(C'\fR peut s'ancrer a\*` la fin de la chai\*^ne, donc le caracte\*`re de fin de ligne disparai\*^tra lui\-aussi. Ajoutez juste le saut de ligne en sortie, ce qui a l'avantage de conserver les lignes entie\*`rement blanches qui sont vide\*'es par \f(CW\*(C`^\es+\*(C'\fR. .PP .Vb 5 \& while( <> ) \& { \& s/^\es+|\es+$//g; \& print "$_\en"; \& } .Ve .PP Pour une chai\*^ne multi\-lignes, vous pouvez appliquer l'expression rationnelle a\*` chaque ligne logique de la chai\*^ne en ajoutant le modificateur \f(CW\*(C`/m\*(C'\fR (pour \*(L"multi\-lignes\*(R"). Avec ce modificateur, \f(CW\*(C`$\*(C'\fR est reconnu \fIavant\fR un saut de ligne, et donc il n'est pas supprime\*'. Par contre, il supprimera encore le saut de ligne en fin de chai\*^ne. .PP .Vb 1 \& $string =~ s/^\es+|\es+$//gm; .Ve .PP Souvenez-vous que les lignes entie\*`rement blanches vont disparai\*^tre puisque la premie\*`re partie de l'alternative les remplacera par rien. Si vous souhaitez les lignes blanches, il faut faire un peu plus de travail. Au lieu de reconnai\*^tre n'importe quel espace (puisque cela inclut les sauts de ligne), ne reconnaissons que les autres espaces. .PP .Vb 1 \& $string =~ s/^[\et\ef ]+|[\et\ef ]+$//mg; .Ve .Sh "Comment cadrer une chai\*^ne avec des blancs ou un nombre avec des ze\*'ros\ ?" .IX Subsection "Comment cadrer une chai^ne avec des blancs ou un nombre avec des ze'ros?" (Cette re\*'ponse est une contribution de Uri Guttman, avec un coup de main de Bart Lateur). .PP Dans les exemples suivants, \f(CW$pad_len\fR est la longueur dans laquelle vous voulez cadrer la chai\*^ne, \f(CW$text\fR ou \f(CW$num\fR contient la chai\*^ne a\*` cadrer, et \f(CW$pad_char\fR contient le caracte\*`re de remplissage. Vous pouvez utiliser une constante contenant une chai\*^ne d'un seul caracte\*`re a\*` la place de la variable \f(CW$pad_char\fR si vous savez ce que c'est. Et de la me\*^me fac\*,on vous pouvez utiliser un entier a\*` la place de \&\f(CW$pad_len\fR si vous connaissez a\*` l'avance la longueur du cadrage. .PP La me\*'thode la plus simple utilise la fonction \f(CW\*(C`sprintf\*(C'\fR. Elle peut cadrer a\*` gauche et a\*` droite avec des espaces et a\*` gauche avec des ze\*'ros et elle ne tronquera pas le re\*'sultat. La fonction \f(CW\*(C`pack\*(C'\fR peut seulement cadrer des chai\*^nes a\*` droite avec des blancs et elle tronquera le re\*'sultat a\*` la longueur maximale de \f(CW$pad_len\fR. .PP .Vb 3 \& # Cadrage a\*` gauche d'une chai\*^ne avec des blancs (pas de troncature) \& $padded = sprintf("%${pad_len}s", $text); \& $padded = sprintf("%*s", $pad_len, $text); # idem \& \& # Cadrage a\*` droite d'une chai\*^ne avec des blancs (pas de troncature) \& $padded = sprintf("%\-${pad_len}s", $text); \& $padded = sprintf("%\-*s", $pad_len, $text); # idem \& \& # Cadrage a\*` gauche d'un nombre avec 0 (pas de troncature) \& $padded = sprintf("%0${pad_len}d", $num); \& $padded = sprintf("%0*d", $pad_len, $num); # idem \& \& # Cadrage a\*` droite d'un nombre avec 0 (avec troncature) \& $padded = pack("A$pad_len",$text); .Ve .PP Si vous avez besoin de cadrer avec un caracte\*`re autre qu'un blanc ou un ze\*'ro, vous pouvez utiliser une des me\*'thodes suivantes. Elles ge\*'ne\*`rent toutes une chai\*^ne de cadrage avec l'ope\*'rateur \f(CW\*(C`x\*(C'\fR et la combinent avec \f(CW$text\fR. Ces me\*'thodes ne tronquent pas \f(CW$text\fR. .PP Cadrage a\*` gauche et a\*` droite avec n'importe quel caracte\*`re, cre\*'ant une nouvelle chai\*^ne\ : .PP .Vb 2 \& $padded = $pad_char x ( $pad_len \- length( $text ) ) . $text; \& $padded = $text . $pad_char x ( $pad_len \- length( $text ) ); .Ve .PP Cadrage a\*` gauche et a\*` droite avec n'importe quel caracte\*`re, modifiant directement \f(CW$text\fR\ : .PP .Vb 2 \& substr( $text, 0, 0 ) = $pad_char x ( $pad_len \- length( $text ) ); \& $text .= $pad_char x ( $pad_len \- length( $text ) ); .Ve .Sh "Comment extraire une se\*'lection de colonnes d'une chai\*^ne de caracte\*`res\ ?" .IX Subsection "Comment extraire une se'lection de colonnes d'une chai^ne de caracte`res?" Utiliser les fonctions \fIsubstr()\fR ou \fIunpack()\fR, toutes deux documente\*'es dans perlfunc. Ceux qui pre\*'fe\*`rent penser en termes de colonnes pluto\*^t qu'en longueurs de lignes peuvent utiliser ce genre de choses\ : .PP .Vb 10 \& # de\*'terminer le format de unpack ne\*'cessaire pour de\*'couper la \& # sortie d'un ps de Linux \& # les arguments sont les colonnes sur lesquelles de\*'couper \& my $fmt = cut2fmt(8, 14, 20, 26, 30, 34, 41, 47, 59, 63, 67, 72); \& sub cut2fmt { \& my(@positions) = @_; \& my $template = ''; \& my $lastpos = 1; \& for my $place (@positions) { \& $template .= "A" . ($place \- $lastpos) . " "; \& $lastpos = $place; \& } \& $template .= "A*"; \& return $template; \& } .Ve .Sh "Comment calculer la valeur soundex d'une chai\*^ne\ ?" .IX Subsection "Comment calculer la valeur soundex d'une chai^ne?" (contribution de brian d foy) .PP Vous pouvez utiliser le module standard Test::Soundex. Si vous souhaitez faire de la reconnaissance floue et approche\*'e, vous devriez aussi essayer les modules String::Approx, Text::Metaphone et Text::DoubleMetaphone. .Sh "Comment interpoler des variables dans des chai\*^nes de texte\ ?" .IX Subsection "Comment interpoler des variables dans des chai^nes de texte?" Supposons une chai\*^ne comme celle-ci ($bar et \f(CW$foo\fR ne sont pas interpole\*'es)\ : .PP .Vb 1 \& $text = 'this has a $foo in it and a $bar'; .Ve .PP Vous pouvez utiliser une substitution avec une double e\*'valuation. Le premier /e remplace \f(CW$1\fR par \f(CW$foo\fR et le second /e remplace \f(CW$foo\fR par sa valeur. Vous pouvez habiller cela par un \f(CW\*(C`\f(CW\*(C`eval\*(C'\f(CW :\*(C'\fR si vous essayer d'obtenir la valeur d'une variable non de\*'clare\*' et si \f(CW\*(C`use strict\*(C'\fR est actif, vous aurez une erreur fatale. .PP .Vb 2 \& eval { $text =~ s/(\e$\ew+)/$1/eeg }; \& die if $@; .Ve .PP Il serait probablement pre\*'fe\*'rable dans le cas ge\*'ne\*'ral de traiter ces variables comme des entre\*'es dans une table de hachage a\*` part. Par exemple\ : .PP .Vb 5 \& %user_defs = ( \& foo => 23, \& bar => 19, \& ); \& $text =~ s/\e$(\ew+)/$user_defs{$1}/g; .Ve .ie n .Sh "En quoi est-ce un proble\*`me de toujours placer ""$vars"" entre guillemets\ ?" .el .Sh "En quoi est-ce un proble\*`me de toujours placer ``$vars'' entre guillemets\ ?" .IX Subsection "En quoi est-ce un proble`me de toujours placer $vars entre guillemets?" Le proble\*`me est que ces guillemets forcent la conversion en chai\*^ne, imposant aux nombres et aux re\*'fe\*'rences de devenir des chai\*^nes, me\*^me lorsqu'on ne le souhaite pas. Pensez-y de cette fac\*,on\ : l'expansion des guillemets est utilise\*'e pour produire de nouvelles chai\*^nes. Si vous avez de\*'ja\*` une chai\*^ne, pourquoi en vouloir plus\ ? .PP Si l'on prend l'habitude d'e\*'crire des choses bizarres comme c\*,a\ : .PP .Vb 3 \& print "$var"; # MAL \& $new = "$old"; # MAL \& somefunc("$var"); # MAL .Ve .PP on se retrouve vite avec des proble\*`mes. Les constructions suivantes devraient (dans 99.8% des cas) e\*^tre plus simples et plus directes\ : .PP .Vb 3 \& print $var; \& $new = $old; \& somefunc($var); .Ve .PP Autrement, en plus de ralentir, ceci risque de casser le code lorsque ce qui est dans la variable scalaire n'est effectivement ni une chai\*^ne de caracte\*`res, ni un nombre mais une re\*'fe\*'rence\ : .PP .Vb 5 \& func(\e@array); \& sub func { \& my $aref = shift; \& my $oref = "$aref"; # FAUX \& } .Ve .PP On peut aussi se retrouver face a\*` des proble\*`mes subtils pour les quelques ope\*'rations pour lesquels Perl fait effectivement la diffe\*'rence entre une chai\*^ne de caracte\*`res et un nombre, comme pour l'ope\*'rateur magique d'autoincre\*'mentation \f(CW\*(C`++\*(C'\fR, ou pour la fonction \fIsyscall()\fR. .PP La mise en chai\*^ne de\*'truit aussi les tableaux\ : .PP .Vb 3 \& @lines = `command`; \& print "@lines"; # FAUX \- ajoute des blancs \& print @lines; # correct .Ve .Sh "Pourquoi est-ce que mes documents <<\s-1HERE\s0 ne marchent pas\ ?" .IX Subsection "Pourquoi est-ce que mes documents <op_ppaddr)() ); \& @@@ TAINT_NOT; \& @@@ return 0; \& @@@ } \& MAIN_INTERPRETER_LOOP .Ve .PP Ou encore avec une quantite\*' fixe\*'e d'en\-te\*^te d'espaces, tout en conservant correctement l'indentation\ : .PP .Vb 9 \& $poem = fix<. Elle s'arre\*^te de\*`s qu'elle trouve l'e\*'le\*'ment recherche\*'. Elle est e\*'crite en C pour des raisons de performance et son e\*'quivalent en Perl ressemblerait au sous-programme suivant\ : .PP .Vb 7 \& sub first (&@) { \& my $code = shift; \& foreach (@_) { \& return $_ if &{$code}(); \& } \& undef; \& } .Ve .PP Si la performance n'est pas un proble\*`me, une manie\*`re de faire consiste a\*` appliquer a\*` toutes la liste un grep dans un contexte scalaire (il retourne alors le nombre d'items ayant passe\*' la condition). En revanche, vous y gagnez la possibilite\*' de savoir combien de fois l'e\*'le\*'ment est reconnu. .PP .Vb 1 \& my $nb_items = grep $_ eq $element, @tableau; .Ve .PP Si vous souhaitez re\*'cupe\*'rer les e\*'le\*'ments reconnus, utilisez grep dans un contexte de liste. .PP .Vb 1 \& my @reconnus = grep $_ eq $element, @tableau; .Ve .Sh "Comment calculer la diffe\*'rence entre deux tableaux\ ? Comment calculer l'intersection entre deux tableaux\ ?" .IX Subsection "Comment calculer la diffe'rence entre deux tableaux? Comment calculer l'intersection entre deux tableaux?" Utiliser un hachage. Voici un code pour faire les deux et me\*^me plus. Il suppose chaque e\*'le\*'ment dans un tableau donne\*'\ : .PP .Vb 7 \& @union = @intersection = @difference = (); \& %count = (); \& foreach $element (@array1, @array2) { $count{$element}++ } \& foreach $element (keys %count) { \& push @union, $element; \& push @{ $count{$element} > 1 ? \e@intersection : \e@difference }, $element; \& } .Ve .PP Notez que ceci est la \fIdiffe\*'rence syme\*'trique\fR, c'est\-a\*`\-dire tous les e\*'le\*'ments qui sont soit dans A, soit dans B, mais pas dans les deux. Voyez cela comme une ope\*'ration xor (un ou exclusif). .Sh "Comment tester si deux tableaux ou hachages sont e\*'gaux\ ?" .IX Subsection "Comment tester si deux tableaux ou hachages sont e'gaux?" Le code suivant fonctionne pour les tableaux a\*` un seul niveau. Il utilise une comparaison de chai\*^nes, et ne distingue pas les chai\*^nes vides de\*'finies ou inde\*'finies. Modifiez-le si vous avez d'autres besoins. .PP .Vb 1 \& $are_equal = compare_arrays(\e@frogs, \e@toads); \& \& sub compare_arrays { \& my ($first, $second) = @_; \& no warnings; # silence spurious \-w undef complaints \& return 0 unless @$first == @$second; \& for (my $i = 0; $i < @$first; $i++) { \& return 0 if $first\->[$i] ne $second\->[$i]; \& } \& return 1; \& } .Ve .PP Pour les structures a\*` niveau multiples, vous pouvez de\*'sirer utiliser une approche ressemblant plus a\*` celle\-ci. Elle utilise le module \s-1CPAN\s0 FreezeThaw\ : .PP .Vb 2 \& use FreezeThaw qw(cmpStr); \& @a = @b = ( "this", "that", [ "more", "stuff" ] ); \& \& printf "a and b contain %s arrays\en", \& cmpStr(\e@a, \e@b) == 0 \& ? "the same" \& : "different"; .Ve .PP Cette approche fonctionne aussi pour comparer des hachages. Ici, nous allons de\*'montrer deux re\*'ponses diffe\*'rentes\ : .PP .Vb 1 \& use FreezeThaw qw(cmpStr cmpStrHard); \& \& %a = %b = ( "this" => "that", "extra" => [ "more", "stuff" ] ); \& $a{EXTRA} = \e%b; \& $b{EXTRA} = \e%a; \& \& printf "a and b contain %s hashes\en", \& cmpStr(\e%a, \e%b) == 0 ? "the same" : "different"; \& \& printf "a and b contain %s hashes\en", \& cmpStrHard(\e%a, \e%b) == 0 ? "the same" : "different"; .Ve .PP La premie\*`re rapporte que les deux hachages contiennent les me\*^mes donne\*'es, tandis que la seconde rapporte le contraire. Le fait de de\*'terminer celle que vous pre\*'fe\*'rez vous est laisse\*'e en exercice. .Sh "Comment trouver le premier e\*'le\*'ment d'un tableau ve\*'rifiant une condition donne\*'e\ ?" .IX Subsection "Comment trouver le premier e'le'ment d'un tableau ve'rifiant une condition donne'e?" Pour trouver le premier e\*'le\*'ment d'un tableau ve\*'rifiant une condition, vous pouvez utiliser la fonction \f(CW\*(C`first\*(C'\fR du module List::Util (en standard depuis Perl 5.8). L'exemple suivant trouve le premier e\*'le\*'ment contenant \*(L"Perl\*(R". .PP .Vb 1 \& use List::Util qw(first); \& \& my $element = first { /Perl/ } @tableau; .Ve .PP Si vous ne pouvez pas utiliser List::Util, vous pouvez e\*'crire votre propre boucle pour faire la me\*^me chose. De\*`s que vous trouvez l'e\*'le\*'ment voulu, vous stoppez la boucle via \fIlast()\fR. .PP .Vb 5 \& my $found; \& foreach ( @tableau ) \& { \& if( /Perl/ ) { $found = $_; last } \& } .Ve .PP Si vous souhaitez connai\*^tre l'indice de l'e\*'le\*'ment, vous pouvez faire une boucle sur tous les indices du tableau et tester l'e\*'le\*'ment lie\*' a\*` cet indice jusqu'a\*` trouver l'e\*'le\*'ment satisfaisant la condition. .PP .Vb 10 \& my( $found, $index ) = ( undef, \-1 ); \& for( $i = 0; $i < @tableau; $i++ ) \& { \& if( tableau[$i] =~ /Perl/ ) \& { \& $found = tableau[$i]; \& $index = $i; \& last; \& } \& } .Ve .Sh "Comment ge\*'rer des listes chai\*^ne\*'es\ ?" .IX Subsection "Comment ge'rer des listes chai^ne'es?" En ge\*'ne\*'ral, avec Perl, on n'a pas de besoin de liste chai\*^ne\*'e, puisqu'avec des tableaux usuels, on peut ajouter (push/unshift) et enlever (pop/shift) de part et d'autre, ou l'on peut utiliser splice pour ajouter et/ou enlever un nombre arbitraire d'e\*'le\*'ments a\*` un point arbitraire. Pop et shift sont toutes deux des ope\*'rations en O(1) sur les tableaux dynamiques de Perl. En absence de shifts et pops, push a en ge\*'ne\*'ral besoin de faire des re\*'allocations environ toutes les log(N) fois, et unshift aura besoin de copier des pointeurs a\*` chaque fois. .PP Si vous le voulez vraiment, vous pouvez utiliser les structures de\*'crites dans perldsc ou perltoot et faire exactement comme le livre d'algorithmes dit de faire. Par exemple, imaginez un noeud de liste tel que celui-ci\ : .PP .Vb 4 \& $node = { \& VALUE => 42, \& LINK => undef, \& }; .Ve .PP Vous pouvez balayer la liste de cette fac\*,on\ : .PP .Vb 5 \& print "List: "; \& for ($node = $head; $node; $node = $node\->{LINK}) { \& print $node\->{VALUE}, " "; \& } \& print "\en"; .Ve .PP Vous pouvez allonger la liste ainsi\ : .PP .Vb 5 \& my ($head, $tail); \& $tail = append($head, 1); # ajoute un e\*'le\*'ment en te\*^te \& for $value ( 2 .. 10 ) { \& $tail = append($tail, $value); \& } \& \& sub append { \& my($list, $value) = @_; \& my $node = { VALUE => $value }; \& if ($list) { \& $node\->{LINK} = $list\->{LINK}; \& $list\->{LINK} = $node; \& } else { \& $_[0] = $node; # remplace la valeur fournie a\*` l'appel \& } \& return $node; \& } .Ve .PP Mais encore une fois, les fonctions inte\*'gre\*'es de Perl sont presque toujours suffisantes. .Sh "Comment ge\*'rer des listes circulaires\ ?" .IX Subsection "Comment ge'rer des listes circulaires?" Des listes circulaires peuvent e\*^tre ge\*'re\*'es de fac\*,on traditionnelle par des listes chai\*^ne\*'es, ou encore en utilisant simplement quelque chose comme ceci avec un tableau\ : .PP .Vb 2 \& unshift(@array, pop(@array)); # les derniers seront les premiers \& push(@array, shift(@array)); # et vice versa .Ve .Sh "Comment me\*'langer le contenu d'un tableau\ ?" .IX Subsection "Comment me'langer le contenu d'un tableau?" Si vous disposez au moins de la version 5.8.0 de Perl ou si la version 1.03 ou plus de Scalar-List-Utils est installe\*'e, vous pouvez faire\ : .PP .Vb 1 \& use List::Util 'shuffle'; \& \& @melange = shuffle(@tableau); .Ve .PP Sinon, utilisez le me\*'langeur de Fisher-Yates\ : .PP .Vb 8 \& sub melange_de_fisher_yates { \& my $deck = shift; # $deck est une re\*'fe\*'rence a\*` un tableau \& my $i = @$deck; \& while (\-\-$i) { \& my $j = int rand ($i+1); \& @$deck[$i,$j] = @$deck[$j,$i]; \& } \& } \& \& # me\*'lange ma collection de mpeg \& # \& my @mpeg =