=encoding iso-8859-1 =head1 NAME/NOM perlfaq4 - Manipulation de données ($Revision: 1.73 $, $Date: 2005/12/31 00:54:37 $) =head1 DESCRIPTION Cette section de la FAQ répond aux questions liées à la manipulation des nombres, des dates, des chaînes de caractères, des tableaux, des tables de hachage, ainsi qu'à divers problèmes relatifs aux données. =head1 S nombres =head2 Pourquoi est-ce que j'obtiens des longs nombres décimaux (ex. 19.9499999999999) à la place du nombre que j'attends (ex. 19.95)E? En interne, un ordinateur représente les flottants (les nombres à virgule) sous forme binaire. Les ordinateurs ne peuvent pas stocker tous les nombres de manière exacte. Certains nombres réels perdent un peu de précision lors de leur traitement. C'est un problème dû à la manière dont les ordinateurs stockent les nombres et concerne donc tous les langages, pas uniquement Perl. Voir L pour de plus amples informations sur le stockage des nombres et leurs conversions. Pour limiter le nombre de décimales dans un nombre, vous pouvez utiliser les fonctions printf ou sprintf. Voir L pour plus de détails. printf "%.2f", 10/3; my $number = sprintf "%.2f", 10/3; =head2 Pourquoi int() ne fonctionne pas S Votre fonction int() fonctionne certainement très bien. Ce sont les nombres qui ne sont pas ce que vous croyez. Tout d'abord, voyez la question ci-dessus L?">. Par exemple, S print int(0.6/0.2-2), "\n"; affichera 0 et non 1 sur la plupart des ordinateurs, puisque même des nombres aussi simples que 0.6 et 0.2 ne peuvent pas être représentés exactement par des flottants. Ce que vous espériez être 'trois' ci-dessus et en fait quelque chose comme 2.9999999999999995559. =head2 Pourquoi mon nombre octal n'est-il pas interprété S Perl ne comprend les nombres octaux et hexadécimaux en tant que tels que lorsqu'ils sont utilisés comme des valeurs littérales dans le programme. En Perl, les nombres octaux littéraux doivent commencer par "0" et les hexadécimaux par "0x". S'ils sont lus de quelque part et affectés à une variable, aucune conversion automatique n'a lieu. Pour convertir les valeurs, il faut utiliser explicitement oct() ou hex(). oct() interprète à la fois les nombres hexadécimaux ("0x350"), les nombres octaux ("0350" ou même sans le "0" de tête, comme dans "377") et les nombres binaires ("0b1010"), tandis que hex() ne convertit que les hexadécimaux, avec ou sans l'en-tête "0x", comme pour "0x255", "3A", "ff", ou "baffe". Le transformation inverse (depuis décimal vers octal) peut être obtenue via les formats "%o" et "%O" de sprintf(). Ce problème apparaît fréquemment lorsque l'on essaye d'utiliser les fonctions chmod(), mkdir(), umask(), ou sysopen() qui demandent toutes traditionnellement des permissions en octal. chmod(644, $file); # FAUX chmod(0644, $file); # correct Notez l'erreur de la première ligne qui spécifie le nombre décimal 644 au lieu du nombre octal voulu 0644. Le problème apparaît mieux S printf("%#o",644); # affiche 01204 Vous ne vouliez pas dire C... Si vous voulez utilisez des valeurs numériques octales comme arguments de chmod() et autres, alors exprimez les en les préfixant d'un zéro et en n'utilisant ensuite que des chiffres de 0 à 7. =head2 Perl a-t-il une fonction round()E? Et ceil() (majoration) et floor() (minoration)E? Et des fonctions S Il faut retenir que int() ne fait que tronquer vers 0. Pour arrondir à un certain nombre de chiffres, sprintf() ou printf() sont d'habitude la voie la plus simple. printf("%.3f", 3.1415926535); # affiche 3.142 Le module POSIX (élément de la distribution standard de Perl) implémente ceil(), floor(), et d'autres fonctions mathématiques et trigonométriques. use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3 Dans les versions 5.000 à 5.003 de perl, la trigonométrie était faite par le module Math::Complex. À partir de 5.004, le module Math::Trig (élément de la distribution standard de Perl) implémente les fonctions trigonométriques. En interne, il utilise le module Math::Complex, et quelques fonctions peuvent s'échapper de l'axe des réels vers le plan des complexes, comme par exemple le sinus inverse de 2. Les arrondis dans des applications financières peuvent avoir des conséquences majeures, et la méthode utilisée se doit d'être spécifiée précisément. Dans ces cas, il vaut mieux ne pas avoir confiance dans un quelconque système d'arrondis utilisé par Perl, mais implémenter sa propre fonction d'arrondis telle qu'elle est nécessaire. Pour comprendre pourquoi, remarquez comment il vous reste un problème lors d'une progression par cinq S 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 Perl n'est pas en faute. C'est pareil qu'en C. L'IEEE dit que nous devons faire comme ça. Les nombres en Perl dont la valeur absolue est un entier inférieur à 2**31 (sur les machines 32 bit) fonctionneront globalement comme des entiers mathématiques. Les autres nombres ne sont pas garantis. =head2 Comment faire des conversions numériques entre différentes bases, entre différentes S 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 représentations des nombres. Ce n'est pas une liste exhaustive. Certains exemples ci-dessous utilisent le module Bit::Vector du CPAN. Les raisons du choix de Bit::Vector plutôt que des fonctions prédéfinies de perl sont qu'il sait traiter des nombres de n'importe quelle longueur, qu'il est optimisé pour certaines opérations et que sa notation semblera familière au moins à certains programmeurs. =over 4 =item Comment faire une conversion hexadécimal vers décimal En utilisant la conversion interne de perl de la notation S<0x :> $dec = 0xDEADBEEF; En utilisant la fonction S $dec = hex("DEADBEEF"); En utilisant S $dec = unpack("N", pack("H8", substr("0" x 8 . "DEADBEEF", -8))); En utilisant le module Bit::Vector du S use Bit::Vector; $vec = Bit::Vector->new_Hex(32, "DEADBEEF"); $dec = $vec->to_Dec(); =item Comment faire une conversion décimal vers hexadécimal En utilisant S $hex = sprintf("%X", 3735928559); # majuscules A-F $hex = sprintf("%x", 3735928559); # minuscules a-f En utilisant S $hex = unpack("H*", pack("N", 3735928559)); En utilisant S use Bit::Vector; $vec = Bit::Vector->new_Dec(32, -559038737); $hex = $vec->to_Hex(); En utilisant Bit::Vector qui accepte un nombre de bits S use Bit::Vector; $vec = Bit::Vector->new_Dec(33, 3735928559); $vec->Resize(32); # suppression des 0 de remplissage $hex = $vec->to_Hex(); =item Comment faire une conversion octal vers décimal En utilisant la conversion interne de Perl des nombres préfixés par un S $dec = 033653337357; # notez le préfixe 0 ! En utilisant la fonction S $dec = oct("33653337357"); En utilisant Bit::Vector: use Bit::Vector; $vec = Bit::Vector->new(32); $vec->Chunk_List_Store(3, split(//, reverse "33653337357")); $dec = $vec->to_Dec(); =item Comment faire une conversion décimal vers octal En utilisant S $oct = sprintf("%o", 3735928559); En utilisant Bit::Vector: use Bit::Vector; $vec = Bit::Vector->new_Dec(32, -559038737); $oct = reverse join('', $vec->Chunk_List_Read(3)); =item Comment faire une conversion binaire vers décimal Depuis Perl 5.6, vous pouvez écrire les nombres binaires directement via la notation S<0b :> $number = 0b10110110; En utilisant S my $input = "10110110"; $decimal = oct( "0b$input" ); En utilisant pack et S $decimal = ord(pack('B8', '10110110')); En utilisant pack et unpack pour les grands S $int = unpack("N", pack("B32", substr("0" x 32 . "11110101011011011111011101111", -32))); $dec = sprintf("%d", $int); # substr() est utilisée pour compléter le nombre par des zéros # à gauche afin d'obtenir une chaîne de 32 caractères En utilisant S $vec = Bit::Vector->new_Bin(32, "11011110101011011011111011101111"); $dec = $vec->to_Dec(); =item Comment faire une conversion décimal vers binaire En utilisant sprintf (perl 5.6 et plus)E: $bin = sprintf("%b", 3735928559); En utilisant S $bin = unpack("B*", pack("N", 3735928559)); En utilisant S use Bit::Vector; $vec = Bit::Vector->new_Dec(32, -559038737); $bin = $vec->to_Bin(); Les autres conversions (par exemple hex -> oct, bin -> hex, etc.) sont laissées en exercices au lecteur. =back =head2 Pourquoi & ne fonctionne-t-il pas comme je le S Le comportement des opérateurs arithmétiques binaires varie selon qu'ils sont utilisés sur des nombres ou des chaînes. Ces opérateurs traitent une chaîne comme une série de bits et travaillent avec (la chaîne C<"3"> est le motif de bits C<00110011>). Ces opérateurs travaillent avec la forme binaire d'un nombre (le nombre C<3> est traité comme le motif de bits C<00000011>). Le fait de dire C<11 & 3> effectue donc l'opération "et" bit-à-bit sur des nombres (donnant ici C<3>). Le fait de dire C<"11" & "3"> effectue un "et" bit-à-bit sur des chaînes (donnant C<"1">). La plupart des problèmes posés par C<&> et C<|> surviennent parce que le programmeur pense qu'il traite un nombre alors qu'en fait c'est une chaîne. Les autres problèmes se posent parce que le programmeur S if ("\020\020" & "\101\101") { # ... } mais une chaîne constituée de deux octets nuls (le résultat de C<"\020\020" & "\101\101">) n'est pas une valeur fausse en Perl. Vous avez besoin d'S<écrire :> if ( ("\020\020" & "\101\101") !~ /[^\000]/) { # ... } =head2 Comment multiplier des S Utiliser les modules Math::Matrix ou Math::MatrixReal (disponibles sur le CPAN) ou l'extension PDL (également disponible sur le CPAN). =head2 Comment effectuer une opération sur une série d'S Pour appeler une fonction sur chaque élément d'un tableau, et récupérer le résultat, S @results = map { my_func($_) } @array; Par S @triple = map { 3 * $_ } @single; Pour appeler une fonction sur chaque élément d'un tableau, mais sans tenir compte du S foreach $iterator (@array) { some_func($iterator); } Pour appeler une fonction sur chaque entier d'un (petit) intervalle, on B S @results = map { some_func($_) } (5 .. 25); mais il faut être conscient que l'opérateur C<..> crée un tableau de tous les entiers de l'intervalle utilisant beaucoup de mémoire pour de grands intervalles. Il vaut mieux S @results = (); for ($i=5; $i < 500_005; $i++) { push(@results, some_func($i)); } Cette situation a été corrigée dans Perl5.005. L'usage de C<..> dans une boucle C itérera sur l'intervalle, sans créer tout l'intervalle. for my $i (5 .. 500_005) { push(@results, some_func($i)); } ne créera pas une liste de 500E000 entiers. =head2 Comment produire des chiffres S Récupérez et utilisez le module L. =head2 Pourquoi mes nombres aléatoires ne sont-ils pas S Si vous utilisez une version de Perl antérieure à la 5.004, vous devez appeler C une fois au début de votre programme pour ensemencer le générateur de nombres aléatoires. BEGIN { srand() if $] < 5.004 } Les versions 5.004 et supérieures appellent automatiquement C dès le début. N'appelez pas C plus d'une fois -- vous rendriez vos nombres moins aléatoires, plutôt que l'inverse. Les ordinateurs sont doués pour être déterministes et mauvais lorsqu'il s'agit d'être aléatoires (malgré les apparences provoquées par les bogues dans vos programmesE:-). Lisez l'article F par Tom Phoenix dans la collection "Far More Than You Ever Wanted To Know" sur L pour en savoir plus à ce sujet. John von Neumann S S<« Quiconque> tente de produire des nombres aléatoires par des moyens déterministes vit dans le S Si vous désirez des nombres qui soient plus aléatoires que ce que fournit C avec C, jetez aussi un oeil au module Math::TrulyRandom sur le CPAN. Il utilise des imperfections de l'horloge du système pour générer des nombres aléatoires, mais ceci prend un certain temps. Si vous voulez un meilleur générateur pseudo-aléatoire que celui qui vient avec le système d'exploitation, lisez les S<« Numerical> Recipes in S sur L. =head2 Comment obtenir un nombre aléatoire entre X et S C retourne un nombre tel que C<< 0 <= rand($x) < $x >>. Donc perl peut générer un nombre aléatoire entre 0 et la valeur qui sépare I et I. Et donc, pour obtenir un entier entre 10 et 15 inclus, vous pouvez générer un nombre entre 0 et 5 auquel vous ajouterez 10. my $nombre = 10 + int rand( 15-10+1 ); Ensuite, on peut transformer ce calcul pour en faire une fonction générique. Elle choisit un nombre aléatoire entre deux entiers S sub random_int_in ($$) { my($min, $max) = @_; # On suppose que les deux arguments sont eux-mêmes des entiers ! return $min if $min == $max; ($min, $max) = ($max, $min) if $min > $max; return $min + int rand(1 + $max - $min); } =head1 S dates =head2 Comment trouver le jour ou la semaine de S La fonction localtime() retourne le jour de l'année. Appeler sans argument, localtime se base sur l'heure (et la date) courante. $jour_de_l_annee = (localtime)[7]; Le module POSIX propose le jour ou la semaine de l'année dans les formats disponible : use POSIX qw/strftime/; my $jour_de_l_annee = strftime "%j", localtime; my $semaine_de_l_annee = strftime "%W", localtime; Pour obtenir le jour de l'anné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 à localtime. use POSIX qw/strftime/; use Time::Local; my $semaine_de_l_annee = strftime "%W", localtime( timelocal( 0, 0, 0, 18, 11, 1987 ) ); Le module Date::Calc propose deux fonctions pour calculer S 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 ); =head2 Comment trouver le siècle ou le millénaire S Utilisez les fonctions simples S sub trouve_siecle { return int((((localtime(shift || time))[5] + 1999))/100); } sub trouve_millenaire { return 1+int((((localtime(shift || time))[5] + 1899))/1000); } Sur certains systèmes, la fonction strftime() du module POSIX a été étendue d'une façon non standard pour utiliser le format C<%C>, et ils prétendent que cela représente le "siècle". Ce n'est pas le cas, puisque sur la plupart de ces systèmes, cela ne représente que les deux premiers chiffres de l'année à quatre chiffres, et ne peut ainsi pas être utilisé pour déterminer de façon fiable le siècle ou le millénaire courant. =head2 Comment comparer deux dates ou en calculer la S (contribution de brian d foy) 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. =head2 Comment convertir une chaîne de caractères en secondes depuis l'origine des S Si cette chaîne est suffisamment régulière pour avoir toujours le même format, on peut la découper et en passer les morceaux à la fonction C du module standard Time::Local. Autrement, regarder les modules Date::Calc et Date::Manip disponibles sur le CPAN. =head2 Comment trouver le jour du calendrier S (contribution de brian d foy et de Dave Cross) Vous pouvez utiliser le module Time::JulianDay disponible sur le CPAN. Assurez-vous tout de même que c'est bien le jour I que vous voulez. Chacun ayant son idée sur les jours Julien, regardez L pour en savoir plus. Vous pouvez aussi essayer le module DateTime qui sait convertir une date ou une heure en un jour Julien. $ perl -MDateTime -le'print DateTime->today->jd' 2453401.5 Ou le jour Julien modifié $ perl -MDateTime -le'print DateTime->today->mjd' 53401 Ou même le jour de l'année (que certains croient être le jour Julien) $ perl -MDateTime -le'print DateTime->today->doy' 31 =head2 Comment trouver la date d'S (contribution de brian d foy) Utilisez l'un des modules Date. Le module C fait cela simplement et vous donne le même moment (même heure) mais hier. use DateTime; my $hier = DateTime->now->subtract( days => 1 ); print "Hier était $hier\n"; Vous pouvez aussi choisir le module C en utilisant sa fonction Today_and_Now. use Date::Calc qw( Today_and_Now Add_Delta_DHMS ); my @hier = Add_Delta_DHMS( Today_and_Now(), -1, 0, 0, 0 ); print "@hier\n"; De nombreuses personnes essaient d'utiliser le temps plutôt que le calendrier pour gérer les dates en supposant que tous les jours ont une durée de vingt quatre heures. Or pour de nombreuses personnes, ils existent deux jours par an où ce n'est pas S les jours de changement d'heure (l'heure d'été et l'heure d'hiver). Laissez donc les modules faire ce boulot. =head2 Perl a-t-il un problème avec l'an S<2000 ?> Perl est-il compatible an S<2000 ?> Réponse S Non, Perl n'a pas de problème avec l'an 2000. Oui, Perl est compatible an 2000 (si ceci veut dire quelque chose). Toutefois, les programmeurs que vous avez embauchés pour l'utiliser ne le sont probablement pas. Réponse S la question demande une vraie compréhension du problème. Perl est juste tout aussi compatible an 2000 que votre crayon -- ni plus ni moins. Pouvez-vous utilisez votre crayon pour rédiger un mémo non compatible an 2000E? Bien sûr que oui. Est-ce la faute du S Bien sûr que non. Les fonctions de date et d'heure fournies avec Perl (gmtime et localtime) donnent des informations adéquates pour déterminer l'année bien au-delà de l'an 2000 (2038 marque le début des problèmes pour les machines 32-bits). L'année renvoyée par ces fonctions lorsqu'elles sont utilisées dans un contexte de liste est l'année, moins 1900. Pour les années entre 1910 et 1999 ceci est un nombre à deux chiffres I. Pour éviter le problème de l'an 2000, ne traitez tout simplement pas l'année comme un nombre à deux chiffres. Elle ne l'est pas. Quand gmtime() et localtime() sont utilisées dans un contexte scalaire, elles renvoient une chaîne qui contient l'année écrite en entier. Par exemple, C<$timestamp = gmtime(1005613200)> fixe $timestamp à la valeur "Tue Nov 13 01:00:00 2001". Ici encore, il n'y a pas de problème de l'an 2000. Ceci ne veut pas dire que Perl ne peut pas être utilisé pour créer des programmes qui ne respecteront pas l'an 2000. Il peut l'être. Mais un crayon le peut aussi. La faute en revient à l'utilisateur, pas au langage. Au risque d'indisposer la NRA (National Rifle Association)E: «EPerl ne viole pas l'an 2000, les gens le fontE». Pour un exposé plus complet, voir L. =head1 S chaînes de caractères =head2 Comment m'assurer de la validité d'une S (contribution de brian d foy) Il existe plusieurs moyens de vérifier que les valeurs sont bien celles que vous attendez ou que vous acceptez. En plus des exemples spécifiques que vous trouverez dans la FAQ perl, vous pouvez aussi jeter un oeil aux modules dont le nom contient "Assert" ou "Validate" ainsi que d'autres modules comme C. Quelques modules savent valider des types particuliers d'entrées. Par exemple C, C, C et C. =head2 Comment supprimer les caractères d'échappement d'une chaîne de S Cela dépend de que vous entendez par "caractère d'échappement". Les caractères d'échappement d'URL sont traités dans . Les caractères de l'interpréteur de commandes avec des barres obliques inversées (C<\>) sont supprimés S s/\\(.)/$1/g; Ceci ne convertira pas les C<"\n"> ou C<"\t"> ni aucun autre caractère spécial. =head2 Comment enlever des paires de caractères S (contribution de brian d foy) Vous pouvez utiliser l'opérateur de substitution pour trouver des couples de caractères identiques et les remplacer pour un seul caractère. Dans cette substitution, nous cherchons un caractère C<(.)>. Les parenthèses de mémorisation stockent le caractère reconnu dans la référence C<\1> que nous utilisons immédiatement pour reconnaître le même caractère une seconde fois. Nous remplaçons ensuite ce couple de caractères par le caractère C<$1> (qui est l'équivalent de C<\1> mais dans la chaîne de remplacement). s/(.)\1/$1/g; On peut aussi utiliser l'opérateur de translittération, C. Dans cet exemple, la liste de recherche est vide mais nous ajoutons le modificateur C pour utiliser en fait le complémentaire de cette liste, c'est à dire tout. La liste de remplacement, elle aussi, ne contient rien et donc la translittération est une opération vide puisque nous n'effectuons aucun remplacement (ou plus exactement, nous remplaçons chaque caractère par lui-même). Par contre, comme nous avons ajouter le modificateur C, les caractères consécutifs identiques sont remplacés par une seule occurrence. my $str = 'Haarlem'; # aux Pays-bas $str =~ tr//cs; # Harlem, comme à New-York =head2 Comment effectuer des appels de fonction dans une S (contribution de brian d foy) Ceci est documenté dans L et, bien que ce ne soit pas la chose la plus facile à lire, ça marche. Dans chacun des exemples suivants, nous appelons la fonction à l'intérieur des accolades en utilisant le déréférencement d'une référence. Si nous avons plus d'un seul résultat, nous pouvons construire et déréfencer un tableau anonyme. Dans ce cas, nous appelons la fonction dans un contexte de S print "The time values are @{ [localtime] }.\n"; 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 référence à un S print "La date est ${\(scalar localtime)}.\n" print "La date est ${ my $x = localtime; \$x }.\n"; Si votre fonction retourne déjà une référence, vous n'avez pas besoin de la construire vous-même : sub timestamp { my $t = localtime; \$t } print "La date est ${ timestamp() }.\n"; Le module C peut aussi faire un peu de magie pour vous. Vous pouvez spécifier un nom, dans notre cas C, liée à une table de hachage qui fera l'interpolation pour vous. Il y a encore plusieurs autres moyens de faire cela. use Interpolation E => 'eval'; print "The time values are $E{localtime()}.\n"; Dans la plupart des cas, il est probablement plus simple d'utiliser la concaténation de chaîne qui impose un contexte S print "La date est " . localtime . ".\n"; =head2 Comment repérer des éléments appariés ou S Ceci ne peut être réalisé en une seule expression régulière, même très compliquée. Pour trouver quelque chose se situant entre deux caractères simples, un motif comme C mettra les morceaux de l'intervalle dans $1. Lorsque le séparateur est de plusieurs caractères, il faudrait en utiliser un ressemblant plus à C. Mais aucun de des deux ne gère les motifs imbriqués. Pour les expressions imbriquées utilisant C<(>, C<{>, C([} ou C<< < >> comme délimiteurs, utilisez le module CPAN Regexp::Common ou voyez L. Pour les autres cas, il vous faudra écrire un analyseur. Si vous songez sérieusement à écrire un analyseur syntaxique, de nombreux modules ou gadgets pourront vous rendre la vie plus facile. Il y a les modules du CPAN Parse::RecDescent, Parse::Yapp et Text::Balanced ainsi que le programme byacc. Depuis perl 5.8, Text::Balanced fait partie de la distribution standard. Une approche simple, mais destructive, consiste à partir de l'intérieur pour aller vers l'extérieur en retirant les plus petites parties imbriquées les unes après les S while (s/BEGIN((?:(?!BEGIN)(?!END).)*)END//gs) { # faire quelque chose de $1 } Une approche plus complexe et contorsionné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 plutôt l'allure d'une entrée de l'Obfuscated Perl Contest, mais ce code fonctionne S # $_ contient la chaîne à analyser # BEGIN et END sont les marqueurs ouvrant et fermants pour le # texte inclus. @( = ('(',''); @) = (')',''); ($re=$_)=~s/((BEGIN)|(END)|.)/$)[!$3]\Q$1\E$([!$2]/gs; @$ = (eval{/$re/},$@!~/unmatched/i); print join("\n",@$[0..$#$]) if( $$[-1] ); =head2 Comment inverser une chaîne de S Utiliser reverse() dans un contexte scalaire, tel qu'indiqué dans L. $reversed = reverse $string; =head2 Comment développer les tabulations dans une chaîne de S On peut le faire S 1 while $string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; Ou utiliser simplement le module Text::Tabs (qui fait partie de la distribution standard de Perl). use Text::Tabs; @expanded_lines = expand(@lines_with_tabs); =head2 Comment remettre en forme un S Utiliser Text::Warp (qui fait partie de la distribution standard de Perl)E: use Text::Wrap; print wrap("\t", ' ', @paragraphs); Les paragraphes passés en argument à Text::Warp ne doivent pas contenir de caractère de saut de ligne. Text::Wrap ne justifie pas les lignes (alignées à droite). Ou utilisez le module CPAN Text::Autoformat. Les formatage de fichiers s'effectue aisément via un alias shell S alias fmt="perl -i -MText::Autoformat -n0777 \ -e 'print autoformat $_, {all=>1}' $*" Voir la documentation de Text::Autoformat pour connaître toutes ses possibilités. =head2 Comment accéder à ou modifier N caractères d'une chaîne de S Vous pouvez accéder aux premiers caractères d'une chaîne via substr(). Pour obtenir le premier caractère, par exemple, commencer à la position 0 et récupérer une sous-chaîne de longueur 1. $string = "Just another Perl Hacker"; $first_char = substr( $string, 0, 1 ); # 'J' Pour modifier une partie d'une chaîne, vous pouvez utiliser le quatrième argument optionnel qui est la chaîne de remplacement. substr( $string, 13, 4, "Perl 5.8.0" ); Vous pouvez aussi utiliser substr() en tant que S substr($a, 0, 3) = "Tom"; =head2 Comment changer la nième occurrence de quelque S Il faut conserver soi-même l'évolution de n. Par exemple, si l'on souhaite changer la cinquième occurrence de C<"whoever"> ou C<"whomever"> en C<"whosoever"> ou C<"whomsoever">, sans tenir compte de la casse. Supposons dans la suite que $_ contienne la chaîne à modifier. $count = 0; s{((whom?)ever)}{ ++$count == 5 # Est-ce la cinquième ? ? "${2}soever" # oui: faire l'échange : $1 # non: le laisser tel quel }ige; Dans des cas plus généraux, on peut utiliser le modificateur C dans une boucle C, en comptant le nombre de correspondances. $WANT = 3; $count = 0; $_ = "One fish two fish red fish blue fish"; while (/(\w+)\s+fish\b/gi) { if (++$count == $WANT) { print "The third fish is a $1 one.\n"; } } Ceci sort: C<"The third fish is a red one."> On peut aussi utiliser un compteur de répétition, et un motif répété comme S /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i; =head2 Comment compter le nombre d'occurrences d'une sous-chaîne dans une chaîne de S Plusieurs moyens sont possibles, avec une efficacité variable. Pour trouver le nombre d'un caractère particulier (X) dans une chaîne, on peut utiliser la fonction C comme S $string = "ThisXlineXhasXsomeXx'sXinXit"; $count = ($string =~ tr/X//); print "There are $count X characters in the string"; Ceci marche bien lorsque l'on cherche un seul caractère. Cependant si l'on essaye de compter des sous-chaînes de plusieurs caractères à l'intérieur d'une chaîne plus grande, C ne marchera pas. On peut alors envelopper d'une boucle while() une recherche de motif globale. Par exemple, comptons les entiers S $string = "-9 55 48 -2 23 -76 4 14 -44"; while ($string =~ /-\d+/g) { $count++ } print "There are $count negative numbers in the string"; Une autre manière de faire utilise la reconnaissance globale dans un contexte de liste puis assigne le résultat à un scalaire, produisant ainsi le nombre de reconnaissances. $count = () = $string =~ /-\d+/g; =head2 Comment mettre en majuscule toutes les premières lettre des mots d'une S Pour mettre en lettres majuscules toutes les premières lettres des S $line =~ s/\b(\w)/\U$1/g; Ceci a pour effet de bord de transformer "C" en "C". C'est parfois ce qu'on veut. Sinon, on peut préférer cette solution (suggérée par brian d foy)E: $string =~ s/ ( (^\w) #au début d'une ligne | # ou (\s\w) #précédé d'un espace ) /\U$1/xg; $string =~ /([\w']+)/\u\L$1/g; Pour transformer toute la ligne en lettres S $line = uc($line); À l'inverse, pour avoir chaque mot en lettres minuscules, avec la première lettre S $line =~ s/(\w+)/\u\L$1/g; On peut (et l'on devrait toujours) rendre ces caractères sensibles aux locales en plaçant une directive C dans le programme. Voir L pour d'interminables détails sur les locales. On s'y réfère parfois comme consistant à mettre quelque chose en "casse de titre", mais ce n'est pas tout à fait juste. Observez la capitalisation correcte du film I How I Learned to Stop Worrying and Love the Bomb>, par exemple. (S d'autant que l'usage en français est de ne mettre de majuscule qu'en début de phrase et aux noms propres.) Le module Text::Autoformat de Domian Conway fournit quelques transformations S use Text::Autoformat; my $x = "Dr. Strangelove or: How I Learned to Stop ". "Worrying and Love the Bomb"; print $x, "\n"; for my $style (qw( sentence title highlight )) { print autoformat($x, { case => $style }), "\n"; } =head2 Comment découper une chaîne séparée par un [caractère] sauf à l'intérieur d'un [caractère]E? Plusieurs modules savent gérer ce genre d'analyses -- Text::Balanced, Text::CSV, Text::CSV_XS et Text::ParseWord parmi d'autres. Prenons l'exemple du cas où l'on souhaite découper une chaîne qui est subdivisée en différents champs par des virgules. On ne peut utiliser C parce qu'il ne faudrait pas découper si la virgule est entre guillemets. Par exemple pour la ligne de donnée S SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped" À cause de la restriction imposée par les guillemets, ceci devient un problème relativement complexe. Heureusement, nous avons Jeffrey Frield, auteur du livre I, qui s'est penché sur le problème pour nous. Il suggère (en supposant que $text contient la chaîne)E: @new = (); push(@new, $+) while $text =~ m{ "([^\"\\]*(?:\\.[^\"\\]*)*)",? # regroupe les éléments entre guillemets | ([^,]+),? | , }gx; push(@new, undef) if substr($text,-1,1) eq ','; Pour représenter un vrai guillemet à l'intérieur d'un champ délimité par des guillemets, il faut le protéger d'une barre oblique inverse comme caractère d'échappement (c.-à-d. C<"comme \"ceci\"">). Comme autre choix, le module Text::ParseWords (qui fait partie de la distribution standard de Perl) permet de S use Text::ParseWords; @new = quotewords(",", 0, $text); Il existe aussi un module Text::CSV (Comma-Separated Values -- Valeurs séparées par des virgules) sur le CPAN. =head2 Comment supprimer des espaces blancs au début/à la fin d'une S (contribution de brian d foy) Une substitution peut le faire pour vous. Pour une simple ligne, vous voulez remplacer tous les espaces en début et en fin de ligne par rien du tout. Cette double substitution le fait : s/^\s+//; s/\s+$//; Vous pourriez aussi l'écrire en une seule substitution bien que ce soit plus lent. Mais ce n'est peut-être pas important pour vous. s/^\s+|\s+$//g; Dans cette expression rationnelle, l'alternative est reconnue soit en début soit en fin de chaîne puisque les ancres ont une précédence plus faible que l'alternative. Avec le modificateur C, la substitution s'effectue partout où elle est reconnue, et donc au début et à la fin. Souvenez-vous que C<\s+> reconnaît les caractères de fin de ligne et que C<$> peut s'ancrer à la fin de la chaîne, donc le caractère de fin de ligne disparaîtra lui-aussi. Ajoutez juste le saut de ligne en sortie, ce qui a l'avantage de conserver les lignes entièrement blanches qui sont vidées par C<^\s+>. while( <> ) { s/^\s+|\s+$//g; print "$_\n"; } Pour une chaîne multi-lignes, vous pouvez appliquer l'expression rationnelle à chaque ligne logique de la chaîne en ajoutant le modificateur C (pour "multi-lignes"). Avec ce modificateur, C<$> est reconnu I un saut de ligne, et donc il n'est pas supprimé. Par contre, il supprimera encore le saut de ligne en fin de chaîne. $string =~ s/^\s+|\s+$//gm; Souvenez-vous que les lignes entièrement blanches vont disparaître puisque la premiè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 reconnaître n'importe quel espace (puisque cela inclut les sauts de ligne), ne reconnaissons que les autres espaces. $string =~ s/^[\t\f ]+|[\t\f ]+$//mg; =head2 Comment cadrer une chaîne avec des blancs ou un nombre avec des S (Cette réponse est une contribution de Uri Guttman, avec un coup de main de Bart Lateur). Dans les exemples suivants, C<$pad_len> est la longueur dans laquelle vous voulez cadrer la chaîne, C<$text> ou C<$num> contient la chaîne à cadrer, et C<$pad_char> contient le caractère de remplissage. Vous pouvez utiliser une constante contenant une chaîne d'un seul caractère à la place de la variable C<$pad_char> si vous savez ce que c'est. Et de la même façon vous pouvez utiliser un entier à la place de C<$pad_len> si vous connaissez à l'avance la longueur du cadrage. La méthode la plus simple utilise la fonction C. Elle peut cadrer à gauche et à droite avec des espaces et à gauche avec des zéros et elle ne tronquera pas le résultat. La fonction C peut seulement cadrer des chaînes à droite avec des blancs et elle tronquera le résultat à la longueur maximale de C<$pad_len>. # Cadrage à gauche d'une chaîne avec des blancs (pas de troncature) $padded = sprintf("%${pad_len}s", $text); $padded = sprintf("%*s", $pad_len, $text); # idem # Cadrage à droite d'une chaîne avec des blancs (pas de troncature) $padded = sprintf("%-${pad_len}s", $text); $padded = sprintf("%-*s", $pad_len, $text); # idem # Cadrage à 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 à droite d'un nombre avec 0 (avec troncature) $padded = pack("A$pad_len",$text); Si vous avez besoin de cadrer avec un caractère autre qu'un blanc ou un zéro, vous pouvez utiliser une des méthodes suivantes. Elles génèrent toutes une chaîne de cadrage avec l'opérateur C et la combinent avec C<$text>. Ces méthodes ne tronquent pas C<$text>. Cadrage à gauche et à droite avec n'importe quel caractère, créant une nouvelle S $padded = $pad_char x ( $pad_len - length( $text ) ) . $text; $padded = $text . $pad_char x ( $pad_len - length( $text ) ); Cadrage à gauche et à droite avec n'importe quel caractère, modifiant directement C<$text>E: substr( $text, 0, 0 ) = $pad_char x ( $pad_len - length( $text ) ); $text .= $pad_char x ( $pad_len - length( $text ) ); =head2 Comment extraire une sélection de colonnes d'une chaîne de S Utiliser les fonctions substr() ou unpack(), toutes deux documentées dans L. Ceux qui préfèrent penser en termes de colonnes plutôt qu'en longueurs de lignes peuvent utiliser ce genre de S # déterminer le format de unpack nécessaire pour découper la # sortie d'un ps de Linux # les arguments sont les colonnes sur lesquelles dé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; } =head2 Comment calculer la valeur soundex d'une S (contribution de brian d foy) Vous pouvez utiliser le module standard Test::Soundex. Si vous souhaitez faire de la reconnaissance floue et approchée, vous devriez aussi essayer les modules String::Approx, Text::Metaphone et Text::DoubleMetaphone. =head2 Comment interpoler des variables dans des chaînes de S Supposons une chaîne comme celle-ci ($bar et $foo ne sont pas interpolées)E: $text = 'this has a $foo in it and a $bar'; Vous pouvez utiliser une substitution avec une double évaluation. Le premier /e remplace C<$1> par C<$foo> et le second /e remplace C<$foo> par sa valeur. Vous pouvez habiller cela par un C :> si vous essayer d'obtenir la valeur d'une variable non déclaré et si C est actif, vous aurez une erreur fatale. eval { $text =~ s/(\$\w+)/$1/eeg }; die if $@; Il serait probablement préférable dans le cas général de traiter ces variables comme des entrées dans une table de hachage à part. Par S %user_defs = ( foo => 23, bar => 19, ); $text =~ s/\$(\w+)/$user_defs{$1}/g; =head2 En quoi est-ce un problème de toujours placer "$vars" entre S Le problème est que ces guillemets forcent la conversion en chaîne, imposant aux nombres et aux références de devenir des chaînes, même lorsqu'on ne le souhaite pas. Pensez-y de cette S l'expansion des guillemets est utilisée pour produire de nouvelles chaînes. Si vous avez déjà une chaîne, pourquoi en vouloir S Si l'on prend l'habitude d'écrire des choses bizarres comme S<ça :> print "$var"; # MAL $new = "$old"; # MAL somefunc("$var"); # MAL on se retrouve vite avec des problèmes. Les constructions suivantes devraient (dans 99.8% des cas) être plus simples et plus S print $var; $new = $old; somefunc($var); Autrement, en plus de ralentir, ceci risque de casser le code lorsque ce qui est dans la variable scalaire n'est effectivement ni une chaîne de caractères, ni un nombre mais une S func(\@array); sub func { my $aref = shift; my $oref = "$aref"; # FAUX } On peut aussi se retrouver face à des problèmes subtils pour les quelques opérations pour lesquels Perl fait effectivement la différence entre une chaîne de caractères et un nombre, comme pour l'opérateur magique d'autoincrémentation C<++>, ou pour la fonction syscall(). La mise en chaîne détruit aussi les S @lines = `command`; print "@lines"; # FAUX - ajoute des blancs print @lines; # correct =head2 Pourquoi est-ce que mes documents EEHERE ne marchent S Vérifier les trois points S =over 4 =item Il ne doit pas y avoir d'espace après le EE. =item Il devrait (habituellement) y avoir un point-virgule à la fin. =item On ne peut pas mettre (facilement) d'espace devant la marque. =back Si l'on souhaite indenter le texte du document inséré, on peut faire S # tout à la fois ($VAR = < $remember_the_main = fix<<' MAIN_INTERPRETER_LOOP'; @@@ int @@@ runops() { @@@ SAVEI32(runlevel); @@@ runlevel++; @@@ while ( op = (*op->op_ppaddr)() ); @@@ TAINT_NOT; @@@ return 0; @@@ } MAIN_INTERPRETER_LOOP Ou encore avec une quantité fixée d'en-tête d'espaces, tout en conservant correctement l'S $poem = fix< tableaux =head2 Quelle est la différence entre une liste et un S Un tableau a une longueur variable. Une liste n'en a pas. Un tableau est quelque chose sur laquelle vous pouvez pousser ou retirer des données, alors qu'une liste est un ensemble de valeurs. Certaines personnes font la distinction qu'une liste est une valeur tandis qu'un tableau est une variable. Les sous-programmes se voient passer et renvoient des listes, vous mettez les choses dans un contexte de liste, vous initialisez des tableaux avec des listes, et vous balayez une liste avec foreach(). Les variables C<@> sont des tableaux, les tableaux anonymes sont des tableaux, les tableaux dans un contexte scalaire se comportent comme le nombre de leurs éléments, les sous-programmes accèdent à leurs arguments via le tableau C<@_> et les fonctions push/pop/shift ne fonctionnent que sur les tableaux. Une note au S il n'existe pas de liste dans un contexte scalaire. Lorsque vous dites $scalar = (2, 5, 7, 9); vous utilisez l'opérateur virgule dans un contexte scalaire, c'est donc l'opérateur virgule scalaire qui est utilisé. Il n'y a jamais eu là de liste du S C'est donc la dernière valeur qui est S 9. =head2 Quelle est la différence entre $array[1] et S<@array[1] ?> La première est une valeur scalaire tandis que la seconde est une tranche de tableaux, ce qui en fait une liste avec une seule valeur (scalaire). On est censé utiliser $ lorsque l'on désire une valeur scalaire (le plus souvent) et @ lorsque l'on souhaite une liste avec une seule valeur scalaire à l'intérieur (très, très rarement, presque jamais en fait). Il n'y a souvent pas de différence, mais il arrive que si. Par exemple, S $good[0] = `une commande qui produit plusieurs lignes`; avec @bad[0] = `une commande qui produit plusieurs lignes`; La directive C ou le drapeau B<-w> préviennent lorsque de tels problèmes se présentent. =head2 Comment supprimer les doublons d'une liste ou d'un S (contribution de brian d foy) Utilisez une table de hachage. Lorsque vous pensez à "unique" ou à "doublons", pensez aux "clés de hachage". Si l'ordre des éléments ne compte pas, vous pouvez créer une table de hachage dont vous extrairez les clés. La manière de créer la table de hachage importe peu : il vous suffit d'utiliser C pour récupérer les éléments uniques. my %hachage = map { $_, 1 } @tableau; # ou via une tranche de hachage : @hachage{ @tableau } = (); # ou via un foreach : $hachage{$_} = 1 foreach ( @tableau ); my @unique = keys %hachage; Vous pouvez aussi parcourir tous les éléments et ne conservez que ceux que vous n'avez encore jamais vus. La première fois que la boucle traite un élément, cet élément n'a pas de clé correspondante dans C<%dejavu>. Le condition dans l'instruction commençant par C crée cette clé et récupère immédiatement sa valeur (qui est C) avant de l'incrémenter. Comme cette valeur initiale est fausse, le C n'a pas lieu et la boucle continue en exécutant le C. Lorsque la boucle rencontre à nouveau le même élément, la clé correspondante existe dans la tableau de hachage I cette clé est vraie (puisque sa valeur incrémentée n'est plus undef), et donc le next interrompt cette itération et la boucle passe à l'élément suivant. my @unique = (); my %dejavu = (); foreach my $elem ( @tableau ) { next if $dejavu{ $elem }++; push @unique, $elem; } Vous pouvez écrire cela de manière plus concise en utilisant grep, qui fera la même chose. my %dejavu = (); my @unique = grep { ! $dejavu{ $_ }++ } @tableau; =head2 Comment savoir si une liste ou un tableau inclut un certain S<élément ?> (cette réponse est, en partie, une contribution de Anno Siegel) D'entendre le mot "Iclut" est une Idication qu'on aurait dû utiliser un tableau de hachage, et pas une liste ou un tableau, pour enregistrer ses données. Les hachages sont conçus pour répondre rapidement et efficacement à cette question, alors que les tableaux ne le sont pas. Cela dit il y a plusieurs moyens pour résoudre ce problème. Si vous faites cette requête plusieurs fois sur des valeurs de chaînes arbitraires, le plus rapide est probablement d'inverser le tableau original et de maintenir à jour une table de hachage dont les clefs sont les valeurs du tableau. @blues = qw/azure cerulean teal turquoise lapis-lazuli/; %is_blue = (); for (@blues) { $is_blue{$_} = 1 } Vous pouvez alors regarder si telle couleur ($some_color) est du bleu en testant $is_blue{$some_color}. Il aurait été une bonne idée de conserver les bleus dans un hachage dès le début. Si les valeurs sont de petits entiers positifs, on peut simplement utiliser un tableau indexé. Ce genre de tableau prendra moins de S @primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31); undef @is_tiny_prime; for (@primes) { $is_tiny_prime[$_] = 1 } # ou simplement @istiny_prime[@primes] = (1) x @primes; À partir de là pour vérifier si $some_number est un nombre premier il suffit de tester $is_tiny_prime[$some_number]. Si les valeurs en question sont des entiers plutôt que des chaînes de caractères, on économise un certain espace en utilisant des chaînes de bits à la S @articles = ( 1..10, 150..2000, 2017 ); undef $read; for (@articles) { vec($read,$_,1) = 1 } Et là vérifier si C est vrai pour un C<$n>. Ces méthodes garantissent des test individuels rapides mais nécessitent une réorganisation de la liste ou du tableau original. Cela ne vaut le coup que si vous devez tester plusieurs valeurs du même tableau. Si vous ne devez faire ce test qu'une seule fois, le module standard List::Util exporte la fonction . Elle s'arrête dès qu'elle trouve l'élément recherché. Elle est écrite en C pour des raisons de performance et son équivalent en Perl ressemblerait au sous-programme S sub first (&@) { my $code = shift; foreach (@_) { return $_ if &{$code}(); } undef; } Si la performance n'est pas un problème, une manière de faire consiste à appliquer à toutes la liste un grep dans un contexte scalaire (il retourne alors le nombre d'items ayant passé la condition). En revanche, vous y gagnez la possibilité de savoir combien de fois l'élément est reconnu. my $nb_items = grep $_ eq $element, @tableau; Si vous souhaitez récupérer les éléments reconnus, utilisez grep dans un contexte de liste. my @reconnus = grep $_ eq $element, @tableau; =head2 Comment calculer la différence entre deux S Comment calculer l'intersection entre deux S Utiliser un hachage. Voici un code pour faire les deux et même plus. Il suppose chaque élément dans un tableau S @union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element; } Notez que ceci est la I, c'est-à-dire tous les éléments qui sont soit dans A, soit dans B, mais pas dans les deux. Voyez cela comme une opération xor (un ou exclusif). =head2 Comment tester si deux tableaux ou hachages sont S<égaux ?> Le code suivant fonctionne pour les tableaux à un seul niveau. Il utilise une comparaison de chaînes, et ne distingue pas les chaînes vides définies ou indéfinies. Modifiez-le si vous avez d'autres besoins. $are_equal = compare_arrays(\@frogs, \@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; } Pour les structures à niveau multiples, vous pouvez désirer utiliser une approche ressemblant plus à celle-ci. Elle utilise le module CPAN S use FreezeThaw qw(cmpStr); @a = @b = ( "this", "that", [ "more", "stuff" ] ); printf "a and b contain %s arrays\n", cmpStr(\@a, \@b) == 0 ? "the same" : "different"; Cette approche fonctionne aussi pour comparer des hachages. Ici, nous allons démontrer deux réponses S use FreezeThaw qw(cmpStr cmpStrHard); %a = %b = ( "this" => "that", "extra" => [ "more", "stuff" ] ); $a{EXTRA} = \%b; $b{EXTRA} = \%a; printf "a and b contain %s hashes\n", cmpStr(\%a, \%b) == 0 ? "the same" : "different"; printf "a and b contain %s hashes\n", cmpStrHard(\%a, \%b) == 0 ? "the same" : "different"; La première rapporte que les deux hachages contiennent les mêmes données, tandis que la seconde rapporte le contraire. Le fait de déterminer celle que vous préférez vous est laissée en exercice. =head2 Comment trouver le premier élément d'un tableau vérifiant une condition S Pour trouver le premier élément d'un tableau vérifiant une condition, vous pouvez utiliser la fonction C du module List::Util (en standard depuis Perl 5.8). L'exemple suivant trouve le premier élément contenant "Perl". use List::Util qw(first); my $element = first { /Perl/ } @tableau; Si vous ne pouvez pas utiliser List::Util, vous pouvez écrire votre propre boucle pour faire la même chose. Dès que vous trouvez l'élément voulu, vous stoppez la boucle via last(). my $found; foreach ( @tableau ) { if( /Perl/ ) { $found = $_; last } } Si vous souhaitez connaître l'indice de l'élément, vous pouvez faire une boucle sur tous les indices du tableau et tester l'élément lié à cet indice jusqu'à trouver l'élément satisfaisant la condition. my( $found, $index ) = ( undef, -1 ); for( $i = 0; $i < @tableau; $i++ ) { if( tableau[$i] =~ /Perl/ ) { $found = tableau[$i]; $index = $i; last; } } =head2 Comment gérer des listes S En général, avec Perl, on n'a pas de besoin de liste chaîné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'éléments à un point arbitraire. Pop et shift sont toutes deux des opérations en O(1) sur les tableaux dynamiques de Perl. En absence de shifts et pops, push a en général besoin de faire des réallocations environ toutes les log(N) fois, et unshift aura besoin de copier des pointeurs à chaque fois. Si vous le voulez vraiment, vous pouvez utiliser les structures décrites dans L ou L et faire exactement comme le livre d'algorithmes dit de faire. Par exemple, imaginez un noeud de liste tel que S $node = { VALUE => 42, LINK => undef, }; Vous pouvez balayer la liste de cette S print "List: "; for ($node = $head; $node; $node = $node->{LINK}) { print $node->{VALUE}, " "; } print "\n"; Vous pouvez allonger la liste S my ($head, $tail); $tail = append($head, 1); # ajoute un élément en tê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 à l'appel } return $node; } Mais encore une fois, les fonctions intégrées de Perl sont presque toujours suffisantes. =head2 Comment gérer des listes S Des listes circulaires peuvent être gérées de façon traditionnelle par des listes chaînées, ou encore en utilisant simplement quelque chose comme ceci avec un S unshift(@array, pop(@array)); # les derniers seront les premiers push(@array, shift(@array)); # et vice versa =head2 Comment mélanger le contenu d'un S 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 installée, vous pouvez S use List::Util 'shuffle'; @melange = shuffle(@tableau); Sinon, utilisez le mélangeur de S sub melange_de_fisher_yates { my $deck = shift; # $deck est une référence à un tableau my $i = @$deck; while (--$i) { my $j = int rand ($i+1); @$deck[$i,$j] = @$deck[$j,$i]; } } # mélange ma collection de mpeg # my @mpeg =