FAQ PerlConsultez toutes les FAQ

Nombre d'auteurs : 18, nombre de questions : 250, dernière mise à jour : 29 octobre 2015  Ajouter une question

 

Bienvenue sur la FAQ Perl. Cette FAQ a pour vocation de vous enseigner ou de vous faire revoir les notions élémentaires de ce fantastique langage. Perl est très utilisé dans différents domaines depuis la gestion système, le réseaux, l'administration de bases de données, le web (CGI), la bureautique, la conception d'interfaces graphiques ou des contextes scientifiques telle la bioinformatique. Nous espérons que cette FAQ vous sera d'une grande utilité.

Vous souhaitez participer à l'amélioration de cette FAQ, n'hésitez pas !! Commentez

Bonne lecture !


SommaireS'initier à PerlListes (13)
précédent sommaire suivant
 

Nous avons vu que Perl gérait des variables scalaires, c'est-à-dire atomiques. Il est aussi capable de gérer des types de variables un peu plus complexes, qu'il sera possible de décomposer en scalaires. Ces types "agrégés" sont principalement au nombre de deux :

  • les listes simples, que l'on rapprochera de la notion de table et qui font l'objet de ce chapitre ;
  • les listes associatives, ou tables associatives, qui feront l'objet du chapitre suivant.

Mis à jour le 5 mai 2005 2Eurocents

Une liste simple ou ordinaire est un type de variable particulier contenant des scalaires.
Une liste s'exprime par une ou plusieurs valeurs séparées par des virgules et mises entre parenthèses :

Code perl : Sélectionner tout
my @list = (1, $toto, 'Hello World', "Histoire de $toto", 3.1415);
C'est l'expression d'une liste rassemblant la valeur entière 1, le contenu du scalaire $toto, la chaîne 'Hello World', la chaîne constituée par la jonction entre "Histoire de " et le contenu du scalaire $toto et pour finir, la valeur flottante 3.1415.
La nature des scalaires contenus dans une liste n'a absolument aucune espèce d'importance pour Perl comme on vient de le voir, mais fonctionnellement le programmeur a peut-être intérêt à veiller à la consistance des données.
Il est possible de constituer les listes en utilisant quelques opérateurs spécifiques. L'opérateur d'intervalle (que l'on n'a pas encore abordé) ".." crée explicitement une liste commençant à la valeur qui le précède et se termine à la valeur qui le suit (sous réserve d'une certaine cohérence de type).

Opérateur .. :
  • (5..15) crée une liste de tous les entiers de 5 à 15 ;
  • (-5..5) crée une liste des entiers de -5 à 5 ;
  • ('a'..'f') crée une liste de tous les caractères de 'a' à 'f' ;
  • ('A'..'F') crée une liste de tous les caractères de 'A' à 'F' (distincte de la précédente - attention à la casse !) ;
  • ('a'..'F') crée une liste des caractères de 'a' à 'z' et (A..f) crée une liste des caractères de 'A' à 'Z'. En effet, la génération de liste part de la première valeur, et monte jusqu'à essayer de rencontrer la dernière. Malheureusement, elle bute en cours de route sur la limite de cohérence de l'ensemble ('z' pour les minuscules et 'Z' pour les majuscules) et elle s'y arrête ;
  • ('aaaa'..'zzzz') crée une liste de toutes les combinaisons de 4 lettres minuscules (déjà beaucoup... qui a dit "attaque brute-force ?).

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/perl 
use warnings; 
use strict; 
  
my @exemple1 = ( 5 .. 15 ); 
my @exemple2 = ( -5 .. 5 ); 
my @exemple3 = ( 'a' .. 'f' ); 
my @exemple4 = ( 'A' .. 'F' ); 
my @exemple5 = ( 'a' .. 'F' ); 
my @exemple6 = ( 'aa' .. 'dd' ); 
print "@exemple1\n";    # 5 6 7 8 9 10 11 12 13 14 15 
print "@exemple2\n";    # -5 -4 -3 -2 -1 0 1 2 3 4 5 
print "@exemple3\n";    # a b c d e f 
print "@exemple4\n";    # A B C D E F 
print "@exemple5\n";    # a b c d e f g h i j k l m n o p q r s t u v w x y z 
print "@exemple6\n";    # a b c d e f g h i j k l m n o p q r s t u v w x y z 
# aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb bc bd be bf bg bh 
# bi bj bk bl bm bn bo bp bq br bs bt bu bv bw bx by bz ca cb cc cd ce cf cg ch ci cj ck cl cm cn co cp c 
# cr cs ct cu cv cw cx cy cz da db dc dd
L'opérateur de multiplication x, impose quelques précautions de parenthèses :
  • ('A' x 3, 'B' x 2, 'C') crée une liste constituée de 'AAA', 'BB' et 'C'.
  • (('A') x 3, ('B') x 2, 'C') crée une liste constituée de 'A', 'A', 'A', 'B', 'B' et 'C'. Les parenthèses introduites créent des listes d'un seul élément ('A' ou 'B') qui sont elles-mêmes multipliées ou dupliquées. Les listes étant des éléments entre parenthèses, il est possible d'introduire des listes dans des listes. Les listes qui sont ainsi insérées sont alors "aplaties" dans la liste réceptacle. Cela signifie que l'on n'introduit pas la liste en tant que telle, mais plutôt son contenu.

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
#!/usr/bin/perl 
use warnings; 
use strict; 
  
my @exemple1 = ( 'A' x 3, 'B' x 2, 'C' ); 
my @exemple2 = ( ('A') x 3, ('B') x 2, 'C' ); 
print "@exemple1\n";    # AAA BB C 
print "@exemple2\n";    # A A A B B C
Cette notion d'aplatissement des listes les unes dans les autres est un concept essentiel dans le traitement des ensembles de valeurs par Perl : (1, 2, (3, 4, (5, 6), 7), 8) est une liste dans laquelle on introduit une sous-liste qui contient elle-même une sous-liste. Au final, on obtient une liste "plate", c'est-à-dire sans niveaux d'imbrication, de 8 éléments. Pour conserver le caractère 'list' d'un ensemble de valeurs introduit dans un autre, il sera nécessaire de faire appel à une notion avancée (que l'on verra ultérieurement) : les références.

des parenthèses vides pour définir une liste vide :
  • () définit une liste ne contenant aucun élément.

Code perl : Sélectionner tout
1
2
3
4
5
#!/usr/bin/perl 
use warnings; 
use strict; 
  
my @liste_vide = ();

Mis à jour le 5 mai 2005 2Eurocents djibril

Les listes que l'on vient de voir sont un peu volatiles... nous ne les avons pas encore rangées dans des variables. Elles ne peuvent pas être conservées dans une variable scalaire ordinaire. Perl a besoin de types de variables spéciaux pour gérer les listes. Pour les listes simples, le type utilisé est le type tableau, ou vecteur.

Mis à jour le 5 mai 2005 2Eurocents

Un tableau est une variable dont le sigil (le caractère qui précède le nom) est @ :

Code perl : Sélectionner tout
my @tableau = (1, 2, 3);
L'usage de ce tableau se fait de deux manières, selon que l'on veut le manipuler dans sa globalité, ou bien accéder à un élément particulier. L'accès global au tableau se fait avec la notation en @ :

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
@tableau = ();             # pour vider un tableau 
@tableau = ( 1, 2, 3 );    # pour affecter une liste à un tableau 
  
# pour affecter le contenu d'un tableau à un 
# autre tableau (attention, il s'agit d'une duplication du contenu) 
@tableau = @list; 
  
# pour affecter le contenu de trois tableaux dans un autre 
@tableau = ( @liste1, @liste2, @liste3 ); 
  
# pour ajouter des listes ou des tableaux à un 
# tableau, avant et après les valeurs actuelles 
@tableau = ( @liste_avant, @tableau, @liste_apres );
Une erreur fréquente chez les débutants consiste à affecter un tableau à une valeur scalaire :

Code perl : Sélectionner tout
$i = @tableau;
Ce qui ne fonctionne pas comme on pourrait le souhaiter... En contexte scalaire (quand on l'affecte à un scalaire, ou bien lorsque l'on l'écrit scalar @tableau), un tableau retourne le nombre d'éléments qu'il contient. En contexte scalaire de chaîne, le tableau retourne la liste de ses éléments, séparés par des blancs. Comment forcer ce contexte de scalaire de chaîne ? Tout simplement en encadrant le tableau par des doubles quotes :

Code perl : Sélectionner tout
$contenu = "@tableau";

Mis à jour le 5 mai 2005 2Eurocents

Un tableau contient des scalaires. Pour en récupérer un en particulier, il faut indiquer que l'on veut un scalaire, donc utiliser le sigil $ devant le nom du tableau et indiquer entre crochets lequel en particulier (rang de rangement dans le tableau, le premier ayant pour rang 0).
$tableau[5] correspond donc au scalaire se trouvant en 6e position du tableau. Les indices de tableau sont donc des entiers positifs, commençant à 0.
Il est possible d'utiliser des entiers négatifs pour effectuer un parcours à rebours du tableau - donc en commençant par la fin :

  • $tableau[-1] désigne ainsi le dernier élément du tableau ;
  • $tableau[-2] l'avant-dernier ;
  • $tableau[-3] l'antépénultième, etc.

Mis à jour le 5 mai 2005 2Eurocents

Pour obtenir le contenu d'une liste, il existe trois fonctions nous facilitant la vie : foreach, for et each.

  • foreach: cette instruction permet de parcourir une liste. Son implémentation est optimisée dans l'interpréteur Perl et est plus efficace qu'un for ;
  • for: cette instruction permet de parcourir une liste à partir d'indices ;
  • each: utilisable avec les listes depuis la version perl 5.12, elle permet de parcourir une liste et retourne l'indice de l'élément et sa valeur (et non la clef et sa valeur comme c'est le cas dans les listes associatives).

Voici des exemples simples.

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/perl 
use warnings; 
use strict; 
  
my @fruits = qw/ Orange Mangue Fraise Pomme Kiwi Ananas Prune/; 
  
print "Utilisation des foreach\n"; 
foreach my $fruits (@fruits) { 
  print "$fruits\n"; 
} 
  
print "\nUtilisation de for\n"; 
for ( my $i = 0; $i < scalar(@fruits); $i++ ) { 
  print "$fruits[$i]\n"; 
} 
  
print "\nUtilisation de each (unique depuis perl 5.12)\n"; 
while ( my ( $indice, $valeur ) = each @fruits ) { 
  print "$indice : $valeur\n"; 
}
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Utilisation de foreach 
Orange 
Mangue 
Fraise 
Pomme 
Kiwi 
Ananas 
Prune 
 
Utilisation de for 
Orange 
Mangue 
Fraise 
Pomme 
Kiwi 
Ananas 
Prune 
 
Utilisation de each (uniquement depuis perl 5.12) 
0 : Orange 
1 : Mangue 
2 : Fraise 
3 : Pomme 
4 : Kiwi 
5 : Ananas 
6 : Prune

Mis à jour le 29 juin 2011 djibril

C'est tout simple, on ne le gère pas, Perl s'occupe de tout !
Pour connaître le nombre d'éléments on utilise la fonction scalar.

Code perl : Sélectionner tout
my $nbr = scalar @tableau;
Il est aussi possible de connaître l'indice du dernier élément du tableau, grâce à une combinaison spéciale de sigils devant le nom de tableau.

Code perl : Sélectionner tout
1
2
3
my @tableau = ( 1, 56, 'ClaudeLELOUP' ); 
my $indice_de_fin = $#tableau; 
print $indice_de_fin; # 2
$#tableau retourne donc le rang du dernier élément de tableau (pour mémoire, c'est un nombre, donc un scalaire, d'où le $, et c'est un indice, donc un numéro, d'où le # qui signifie numéro en notation commerciale américaine).

Maintenant, accéder à des éléments hors des bornes du tableau ne pose pas de problème non plus. Perl crée automatiquement tous les éléments intermédiaires en leur affectant une valeur indéfinie (undef) :

Code perl : Sélectionner tout
1
2
my @liste = ( 1 .. 5 ); 
$liste[10] = 1;
crée une liste de 11 éléments (1, 2, 3, 4, 5, undef, undef, undef, undef, undef, 1).
Pour savoir si un élément de tableau existe réellement, c'est-à-dire s'il a été créé explicitement, et pas par extension de tableau, Perl met à notre disposition la fonction exists() qui retourne vrai si l'élément a bien été créé, faux s'il a été obtenu par extension.
Si vous vous souvenez bien des initialisations de variables, il est possible de laisser une variable non initialisée, voire de la vider en lui affectant la valeur undef. Dans ce dernier cas, s'il s'agit d'un élément de tableau, le test avec la fonction defined() retourne faux, puisque la variable est indéfinie, mais le test avec exists() retourne vrai puisque la variable a été explicitement indéfinie. Il faut donc impérativement faire la distinction entre test de définition (defined()) et test d'existence (exists()).

Mis à jour le 5 mai 2005 2Eurocents

L'équivalence liste/tableaux, la gestion automatique de la taille des tableaux, l'aplatissement des listes les unes dans les autres permettent à Perl des constructions très intéressantes :

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
($v1, $v2, $v3) = (10, 20, 30); # est une affectation de trois valeurs, simultanément. Notez que si vous avez plus d'éléments  
# dans la liste de gauche de l'affectation que dans celle de droite, les éléments en trop à gauche recevront la valeur undef.  
# Inversement, si vous avez plus d'éléments à droite du signe égal qu'à gauche, les dernières valeurs à droite seront ignorées. 
  
($v1, $v2, $v3) = ($v2, $v3, $v1); # est une façon intéressante de mélanger/permuter des valeurs de variables scalaires, que vous en  
# ayez 2, 3, ou n à échanger (enfin, pas trop, quand même, pour que ça reste lisible et maintenable). 
  
($valeur, @tableau) = @tableau; # est une très jolie façon de supprimer la première valeur d'un tableau, tout en la récupérant. 
  
(@tableau, $valeur) = @tableau; # ne sert à rien, car le tableau en début de liste récupére toutes les valeurs de l'affectation.  
# Il ne reste rien pour remplir $valeur, qui vaudra alors undef. 
  
($v1, $v2) = @tableau; # met dans $v1 et $v2 les deux premiers scalaires contenus dans le tableau (sans modifier celui-ci),  
# ce qui est à rapprocher du premier exemple donné ici. 
  
($v1, undef, $v2, undef, undef, $v3) = @tableau; # met dans $v1 la première valeur du tableau, dans $v2 la troisième et dans $v3 la sixième.  
# Les autres scalaires du tableau sont ignorés. 
  
my ($a, $b, $c); # et  
my ($a, $b, $c) = (1, 2, 3); # sont les seules façons correctes de faire des déclarations multiples et simultanées de variables.

Mis à jour le 5 mai 2005 2Eurocents

Si vous souhaitez manipuler des portions de listes, il existe un mécanisme délicatement nommé "tranches" qui vous permet de récupérer une liste qui est un sous-ensemble d'une autre. Ce mécanisme a une syntaxe un peu spéciale mais tout à fait explicite. Si l'on travaille sur une liste (ensemble exprimé entre parenthèses), il suffit de suffixer la liste par une expression des indices des valeurs souhaitées, entre crochets.
Cette expression peut être constituée d'indices distincts, séparés par des virgules, et/ou indiquer des intervalles d'indices au moyen de l'opérateur d'intervalles .. :

Code perl : Sélectionner tout
1
2
@l = ('a', 'b', 'c', 'd', 'e', 'f')[2,4,0]; # remplit @l avec la liste ('c', 'e', 'a') 
@l = ('a', 'b', 'c', 'd', 'e', 'f')[0, 2..4]; # remplit @l avec la liste ('a', 'c', 'd', 'e')
Si l'on travaille sur un tableau, dont on souhaite récupérer une tranche, la spécification d'indices a la même forme, mais le nom de tableau doit être précédé du sigil @, car on n'accède pas à un scalaire, mais à un tableau, constitué par cette fameuse tranche :

Code perl : Sélectionner tout
1
2
@l = ('a', 'b', 'c', 'd', 'e', 'f'); 
@sl = @l[2,4,0];
Il est même possible de faire des remplacements dans un tableau, au moyen du mécanisme de tranches :

Code perl : Sélectionner tout
1
2
@l = ('a', 'b', 'c', 'd', 'e', 'f'); 
@l[2,4,0]=(1,2,3);
modifie la liste @l qui vaut alors (3, 'b', 1, 'd', 2, 'f').

Code perl : Sélectionner tout
1
2
@l = qw(a b c d e f); 
@l[1..3]=(1,2,3);
modifie la liste @l qui vaut alors ('a', 1, 2, 3, 'e', 'f'). Pire encore, les mécanismes de tranches et d'aplatissement des listes permettent d'agrandir ou de rétrécir un tableau par le milieu :

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
@l = qw(a b c d e f); 
  
# modifie la liste @l pour qu'elle vaille ('a', 'b', 'c', 1, 2, 3, 'e', 'f') 
# en gros, on remplace l'élément d'indice 3 par la liste (1, 2, 3). 
@l = ( @l[ 0 .. 2 ], ( 1, 2, 3 ), @l[ 4 .. 5 ] ); 
  
@l = qw(a b c d e f); 
@l = ( @l[ 0 .. 1 ], @l[ 4 .. 5 ] );    # supprime 'c' et 'd' dans le tableau @l..

Mis à jour le 5 mai 2005 2Eurocents

Perl contient de nombreuses fonctions gérant les listes et les tableaux. En voici quelques-unes des plus utiles :

  • qw

permet de créer une liste à partir d'une chaîne de caractères. La chaîne est découpée selon les blancs, les tabulations et les sauts de ligne. Chaque "mot" devient alors un élément de liste.
Seuls les espaces, tabulations, et sauts de ligne sont pris en compte. Aucune protection par des quotes ou doubles quotes n'est efficace. On peut ainsi écrire :

Code perl : Sélectionner tout
@l = qw /Cela est beau et bon/;
plutôt que

Code perl : Sélectionner tout
@l = ('Cela', 'est', 'beau', 'et', 'bon');
  • shift

permet de supprimer le premier élément d'un tableau et de retourner sa valeur. Ainsi, $val = shift @t; est finalement équivalent à ($val, @t) = @t;

  • unshift

permet d'ajouter un ou plusieurs éléments au début d'un tableau. unshift (@t, 1, 2, 3); ajoutera (1, 2, 3) au début du tableau @t.

  • pop

permet de supprimer le dernier élément d'un tableau et de retourner cette valeur.

Code perl : Sélectionner tout
1
2
3
4
my @mois = qw/ mars avril septembre decembre/; 
my $dernier = pop @mois;  
# $dernier =  decembre 
# @mois    =  mars avril septembre
  • push

à l'inverse, permet d'ajouter un ou plusieurs éléments en fin de tableau.

  • delete

permet de supprimer un élément d'un tableau. Mais attention, la valeur supprimée est positionnée à undef, il rend donc vrai au test not defined (), et un comptage du nombre d'éléments dans le tableau avec scalar comptabilisera également les éléments supprimés.

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/perl 
use strict; 
use warnings; 
  
my @mois = qw/ mars avril septembre décembre/; 
  
print 'Il y a ', scalar @mois, " élément dans le tableau\n"; 
delete $mois[1];  # Supprimera avril, MAIS, le remplacera par undef 
print 'Il y a ', scalar @mois, " élément dans le tableau\n"; 
print "\n\n\n"; 
  
# Le tableau ressemble à qw/ mars undef septembre décembre / 
foreach my $elt ( @mois ) { 
  print "- $elt\n"; 
}
Code : Sélectionner tout
1
2
3
4
5
6
7
8
Il y a 4 élément dans le tableau 
Il y a 4 élément dans le tableau 
 
- mars 
Use of uninitialized value $elt in concatenation (.) or string at xxxx\test.pl line 14. 
- 
- septembre 
- décembre
Vous remarquerez que le nombre d'éléments du tableau n'a pas changé, qu'avril a bien été remplacé par undef. De plus, le message d'avertissement "Use of uninitialized value $elt in concatenation (.) or string at" signifie que Perl a lu la case où il y avait avril, mais comme elle est à undef, il s'agit d'une valeur non initialisée. Pour pallier cet inconvénient il aurait fallu faire un test avec defined.
Soyez donc prudent ! Regardez la fonction splice qui peut être plus adaptée à vos besoins.

  • split

permet de découper une chaîne selon des marqueurs spécifiques et retourne la liste des éléments résultant de ce découpage. Le marqueur spécifique est indiqué sous la forme d'une expression rationnelle. Sans entrer dans le détail de ceux-ci, voici des exemples :

Code perl : Sélectionner tout
1
2
split / \t\n/, "chaîne à découper";       # effectue le même travail que qw sur la "chaîne à découper". 
split /:/, "root:password:0:0:/bin/bash"; # effectue le découpage d'une ligne de fichier de mots de passe *n*x selon les différents champs séparés par des ":".
  • join

effectue la tache inverse de split. Elle rassemble les éléments de la liste fournie en les concaténant, tout en les séparant par la chaîne indiquée comme premier paramètre. Ainsi join ('...', 1, 2, 3); créera la chaîne "1...2...3".

  • splice (tableau, début, nombre)

Supprime x éléments d'un tableau à partir de l'indice début spécifié.

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
my @mois = qw/ mars avril septembre décembre/; 
print 'Il y a ', scalar @mois, " élément dans le tableau\n"; 
splice @mois,1,2;  # Supprimera définitivement avril et septembre 
print 'Il y a ', scalar @mois, " élément dans le tableau\n"; 
print "\n"; 
  
# Le tableau ressemble à qw/ mars undef septembre décembre / 
foreach my $elt ( @mois ) { 
  print "- $elt\n"; 
}
Code : Sélectionner tout
1
2
3
4
5
Il y a 4 élément dans le tableau 
Il y a 2 élément dans le tableau 
 
- mars 
- décembre

Mis à jour le 5 mai 2005 2Eurocents djibril

Les listes et les tableaux possèdent une grosse ressemblance, un fort lien de parenté, et il arrive fréquemment que des listes se transforment en tableau et réciproquement. Le principal point commun est qu'une liste et un tableau sont tous les deux des collections d'objets scalaires (ces objets peuvent être aussi bien des constantes que des variables). Du coup, certaines des questions ci-dessus peuvent entretenir une certaine confusion entre les deux notions, pour des raisons de simplification nécessaire quand on s'adresse à des débutants. Cette simplification, utile dans un premier temps, est une forme de « mensonge pieux à des enfants »: on ne peut pas tout expliquer tout de suite, donc on simplifie dans un premier temps. Mais, malgré leurs ressemblances et leurs points communs, les listes et les tableaux sont des entités de nature très différente.

Un tableau est une variable contenant une collection de choses et ayant souvent un nom (préfixé par le sigil @) ou au minimum, dans le cas de tableaux anonymes, une adresse mémoire utilisable par le programmeur sous la forme d'une référence. Une liste est une collection de choses n'ayant pas de nom et n'ayant pas non plus d'adresse mémoire utilisable. Une liste est donc par essence éphémère ou volatile puisqu'elle n'est pas stockée sous la forme d'une variable. Une liste n'étant pas une variable, mais une constante, elle n'est donc par essence non modifiable ou non-mutable (elle ne peut pas être une lvalue).

L'affectation suivante utilise une liste pour initialiser un tableau :

Code perl : Sélectionner tout
my @tableau = (1, 2, "trois", 4, 5, "six"); # copie la liste à droite dans le tableau à gauche
La partie gauche de l'affectation est bien un tableau (c'est une variable qui a un nom préfixé par le sigil@). La suite du programme pourra accéder à la variable @tableau ou aux valeurs individuelles qu'elle contient. La partie à droite de l'affectation est une simple liste temporaire : dès l'instruction suivante du programme, elle n'existe plus. Partie! Gone for ever!

Une liste n'étant pas modifiable, les opérateurs dits de listes qui modifient la liste d'origine ne sont en fait pas utilisables sur une liste mais seulement sur un tableau. C'est le cas, en particulier, des fonctions push, pop, shift, unshift, splice et delete. Aucune d'entre elles ne peut fonctionner sur une simple liste. Par exemple, si l'on crée le tableau suivant et y ajoute un élément avec la fonction push(ou unshift), cela fonctionne parfaitement :

Code perl : Sélectionner tout
1
2
3
my @tableau = qw /1 2 3/; 
push @tableau, 4; 
print "@tableau"; " imprime : 1 2 3 4
Mais essayer de faire la même chose avec une liste donne un message d'erreur :

Code perl : Sélectionner tout
push (1, 2, 3), 4; # !! ne marche pas
On obtient le message d'erreur suivant :

Code perl : Sélectionner tout
Type of arg 1 to push must be array (not constant item)
Ce qui explique clairement le problème : une liste est une constante (même si certains éléments de la liste sont des variables), on ne peut pas lui ajouter un élément, alors que ça marche parfaitement avec un tableau.

Un autre exemple, très souvent troublant pour un débutant, des différences entre une liste et un tableau est le résultat de leur évaluation en contexte scalaire. Si l'on évalue un tableau dans un contexte scalaire, on obtient le nombre d'éléments du tableau :

Code perl : Sélectionner tout
1
2
3
my @tableau = (11, 12, 13, 14, 15, 16); 
my $size = @tableau; # évaluation en contexte scalaire 
print $size; # imprime 6, le nombre d'éléments du tableau
On peut aussi tester la même chose de la façon suivante :

Code perl : Sélectionner tout
1
2
my @tableau = (11, 12, 13, 14, 15, 16); 
print scalar @tableau; # imprime aussi 6
Avec une liste, on obtient un résultat complètement différent :

Code perl : Sélectionner tout
1
2
my $var =  (11, 12, 13, 14, 15, 16); 
print $var; # imprime 16
De même :

Code perl : Sélectionner tout
print scalar (11, 12, 13, 14, 15, 16); # imprime 16
Que se passe-t-il ? On a coutume de dire qu'en contexte scalaire, une liste renvoie son dernier élément. C'est effectivement ce qui semble se passer en pratique (et cette interprétation est souvent suffisante dans la pratique), mais l'explication réelle est un un peu plus subtile : les listes n'ont simplement pas d'existence en contexte scalaire. En contexte de liste, l'opérateur virgule sépare les éléments d'une liste. En contexte scalaire, cet opérateur virgule renvoie l'opérande de droite. Donc, si nous avons :

Code perl : Sélectionner tout
print scalar ("toto", "tutu");
L'évaluation de l'expression entre parenthèses (« toto », « tutu ») donnera l'opérande de droite, donc « tutu ». Si l'expression à évaluer à trois membres, par exemple (« toto », « tutu », « tata »), perl évaluera d'abord les deux premiers membres et lui donnera la valeur « tutu », puis évaluera « tutu » et « tata », et trouvera « tata », et ainsi de suite si la liste à évaluer contient d'autres valeurs. En définitive, même si l'explication est un peu fausse, tout se passe comme si une liste évaluée en contexte scalaire retournait son dernier élément.

Dernier point faisant appel à des notions un peu plus avancées : il est possible de prendre une référence sur ce tableau, c'est-à-dire stocker dans une variable scalaire l'adresse du tableau, ce qui constitue un autre moyen d'accéder à son contenu (voir la partie de cette FAQ consacrée aux références pour plus de détails sur le sujet) :

Code perl : Sélectionner tout
1
2
3
my @tableau = (1, 2, "trois", 4, 5, "six"); 
my $tab_ref = \@tableau; # $tab_ref est une référence, une variable pointant sur l'adresse mémoire du tableau 
print  $tab_ref ; # affiche : ARRAY(0x80359c08), ce qui nous dit que $tab_ref est une référence sur un tableau dont l'adresse mémoire est 0x80359c08
Il n'est pas possible de faire la même chose avec une liste :

Code perl : Sélectionner tout
my $list_ref = \(1, 2, "trois", 4, 5, "six"); # !! ne fonctionne pas
Cela ne fonctionne pas, car $list_ref contient maintenant une référence non pas sur la liste, mais sur le dernier élément de la liste :

Code perl : Sélectionner tout
1
2
print $list_ref ; # imprime   SCALAR(0x8034f940) 
print $$list_ref ; # imprime "six"
Ce fonctionnement n'a rien de surprenant, il rejoint ce que nos avons vu lors de l'évaluation d'une liste en contexte scalaire.

Mis à jour le 16 février 2014 Lolo78

À côté des différences importantes vues dans la question précédente, il y a de nombreux cas où une liste et un tableau se comportent de la même façon et un bon nombre des fonctions (sort, map, grep, join, for, foreach, etc.) sont utilisables de la même manière ou presque sur des listes et des tableaux. Seules les fonctions qui modifient un tableau ne sont généralement pas utilisables sur une liste, sauf éventuellement à créer une autre liste.

En fait, de nombreux opérateurs ou instructions de Perl travaillent non sur des tableaux, comme on peut le croire, mais sur des listes. Si vous passez un (ou plusieurs) tableau(x) en paramètre à une fonction, la fonction reçoit en fait une (seule) liste d'alias vers les éléments du (ou des) tableaux, et cette liste d'alias est mise dans le tableau @_. En particulier, s'il y avait plusieurs tableaux en entrée, la fonction n'a aucun moyen de distinguer les différents tableaux, elle ne « voit » qu'une seule grande liste indifférenciée. Il en va de même en sens inverse quand une fonction renvoie plusieurs tableaux : l'instruction appelante ne reçoit en retour qu'une seule liste indifférenciée, et c'est à elle de la stocker éventuellement dans un tableau (ou d'autres variables) si les éléments de la liste doivent encore être manipulés.

Il a été vu lors d'une question précédente que l'on peut accéder aux éléments individuels d'une liste en utilisant un indice entre crochets, exactement comme avec un tableau :

Code perl : Sélectionner tout
my $second = (1, 2, 3, 4)[1]; #second vaut maintenant 2
Cela ne présente pas beaucoup d'intérêt avec une liste codée en dur comme ci-dessus (on pourrait aussi bien écrire : my $second = 2;), mais cette possibilité peut être très utile avec des listes générées par une instruction du programme. Par exemple, la fonction split divise une chaîne de caractère en une liste de sous-chaînes (en utilisant le premier argument comme séparateur). Souvent, on affecte la liste de sous-chaînes produite à un tableau :

Code perl : Sélectionner tout
my @mots = split / /, "La contrepèterie est l'art de décaler les sons.";
Le split génère une liste de huit sous-chaînes que l'on affecte ensuite au tableau @mots. Il arrive toutefois assez souvent, dans ce genre d'utilisation de split, que l'on ait besoin de seulement une ou deux des sous-chaînes générées par l'opérateur. On peut alors prélever une tranche du tableau @mots :

Code perl : Sélectionner tout
my ($mot2, $mot5) = @mots[1, 4]; # le "sigil" à employer ici est bien @ (et non $) parce que l'on récupère non pas un scalaire, mais une collection de deux scalaires
Mais on peut aussi se passer de créer un tableau intermédiaire et récupérer les mots recherchés directement en une seule instruction plus concise :

Code perl : Sélectionner tout
my ($mot2, $mot5)  = (split / /, "La contrepèterie est l'art de décaler les sons.")[1, 4];
De même, on peut parcourir séquentiellement les valeurs d'une liste avec les opérateurs de boucle for ou foreach. Par exemple, l'instruction suivante affiche la table de multiplication par 5 :

Code perl : Sélectionner tout
print $_, " * 5 = ", $_ * 5, "\n" for 1..10;
Ce qui imprime :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
1 * 5 = 5 
2 * 5 = 10 
3 * 5 = 15 
4 * 5 = 20 
5 * 5 = 25 
6 * 5 = 30 
7 * 5 = 35 
8 * 5 = 40 
9 * 5 = 45 
10 * 5 = 50
Ou, si l'on désire un affichage plus « propre » :

Code perl : Sélectionner tout
printf "%2d%s%2d%s", $_, " x 5 = ", $_ * 5, "\n" for 1..10;
Ce qui donne :

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
1 x 5 =  5 
 2 x 5 = 10 
 3 x 5 = 15 
 4 x 5 = 20 
 5 x 5 = 25 
 6 x 5 = 30 
 7 x 5 = 35 
 8 x 5 = 40 
 9 x 5 = 45 
10 x 5 = 50
Cette syntaxe permet aussi de répéter un certain nombre de fois une instruction simple. Supposons par exemple que nous voulions lire un ficher de données en sautant préalablement les six premières lignes d'en-tête. Nous pouvons le faire ainsi :

Code perl : Sélectionner tout
1
2
3
4
5
open my $FH, "<", $file_in or die "Impossible d'ouvrir le fichier $file_in $!"; 
<$fh> for 1..6; # on jette les six premières lignes 
while (my $line = <$fh>) { 
     # traitement des lignes de données ... 
}
De même, si nous avons besoin de lire les éléments d'un tableau en ayant connaissance de leur indice, au lieu de la boucle for de type C :

Code perl : Sélectionner tout
1
2
3
4
my @mois = qw /undef jan feb mar apr may jun jul aug sep oct nov dec/; # première valeur à undef pour que les mois aillent de 1 à 12 (et non 0 à 11) 
for (my $i = 1; $i ++; $i <= 12) { 
     print "Le mois numéro $i de l'année est $mois[$i]\n"; 
}
nous pouvons utiliser une simple liste pour gérer l'indice $i :

Code perl : Sélectionner tout
1
2
3
for my $i (1..12) { 
     print "Le mois numéro $i de l'année est $mois[$i]\n"; 
}
ou de façon encore plus concise :

Code perl : Sélectionner tout
print "Le mois numéro $_ de l'année est $mois[$_]\n" for (1..12);
Un dernier point qui ne sera que très brièvement esquissé ici: beaucoup des opérateurs de listes de Perl reçoivent en entrée et/ou produisent en sortie une liste. Il est possible d'utiliser en entrée d'un opérateur la liste produite en sortie par un autre opérateur. Ainsi, par exemple, l'instruction suivante enchaîne quatre opérateurs de listes, split, sort, foreach et print:

Code perl : Sélectionner tout
print $_, "\n" foreach sort split / /,  "la contrepèterie est l'art de décaler les sons.";
Ce qui imprime les mots de la phrase triés par ordre lexicographique :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
contrepèterie 
de 
décaler 
est 
l'art 
la 
les 
sons.
Une telle suite d'instructions se lit de droite à gauche: la fonction split commence par découper la phrase en entrée en mots individuels et passe cette liste de mots à la fonction sort; cette dernière trie la liste de mots reçus de split et passe la liste triée à l'opérateur foreach, lequel passe ensuite le mots triés un par un à print, qui imprime les mots triés assortis d'un retour à la ligne. On voit qu'il se forme un pipeline dans lequel les données en entrée subissent des transformations successives. Le lecteur intéressé trouvera des informations beaucoup plus détaillées sur ce genre de constructions très puissantes dans ce tutoriel : La programmation fonctionnelle en Perl - Partie 1: les opérateurs de liste.

Mis à jour le 16 février 2014 Lolo78

  • sort

C'est une fonction interne de Perl permettant de trier une liste. Elle retourne une liste triée.

Code perl : Sélectionner tout
1
2
my @mois       = qw/ mars avril septembre decembre/; 
my @mois_tries = sort @mois;                           # avril decembre mars septembre
Les deux listes peuvent être distinctes. La liste d'origine peut être écrasée par le résultat du tri si elle est destinataire de l'affectation.

La fonction sort peut prendre un argument spécial qui est le bloc de comparaison à effectuer entre les éléments de la liste à trier. Il est ainsi possible de trier selon des critères tout à fait personnalisés. Par défaut, le tri se fait dans l'ordre « lexicographique » (ordre alphabétique, étendu aux nombres dont les chiffres sont traités comme des caractères et non comme des nombres). Le bloc de comparaison personnalisé doit être précisé entre accolades, avant la liste d'éléments à trier, sans être séparé de celle-ci par une virgule.

Pour la comparaison, ce bloc utilise deux variables internes de Perl, $a et $b, qui ne sont définies que dans ce bloc et masquent toute variable $a ou $b propre à l'utilisateur. Ce bloc effectue donc un test quelconque, basé sur $a et $b, dont le résultat peut prendre trois valeurs :

  • positif si $a est avant $b dans l'ordre de tri souhaité ;
  • nul si $a et $b sont équivalents ;
  • négatif si $a est après $b dans l'ordre souhaité.

Ces trois valeurs de résultat de test correspondent aux résultats des opérateurs de test <=> et cmp. Ainsi, pour un tri lexicographique du tableau @t, on peut faire :

Code perl : Sélectionner tout
my @mois_tries = sort @mois;
ou bien

Code perl : Sélectionner tout
my @mois_tries = sort { $a cmp $b } @mois;
Pour un tri lexicographique inversé, on peut aussi bien écrire :

Code perl : Sélectionner tout
my @mois_tries = reverse sort @mois;
que

Code perl : Sélectionner tout
my @mois_tries = sort { $b cmp $a } @mois;
bien que cette méthode soit moins performante que la précédente.

Pour un tri numérique :

Code perl : Sélectionner tout
@l = sort { $a <=> $b } @t;
Pour un tri un peu spécial, en supposant que @t contienne des indices d'un tableau et que l'on souhaite un tri de ces indices selon les valeurs numériques du tableau :

Code perl : Sélectionner tout
@l = sort { $tableau[$a] <=> $tableau[$b] } @t;
@l contient alors les valeurs de @t triées dans un ordre tel, qu'elles indicent des valeurs croissantes dans @tableau. C'est très indirect et ce n'est pas forcément très naturel au début, mais c'est extrêmement puissant. Et pour finir, bien que l'on n'ait pas encore abordé la définition de fonctions personnalisées, il est possible d'appeler une fonction définie par le programmeur :

Code perl : Sélectionner tout
@l = sort { mafonction($a, $b) } @t;
  • map

C'est une fonction interne de Perl permettant de parcourir une liste et d'appliquer un traitement à chaque élément de la liste.

Elle retourne la liste des éléments traités.
Comme pour la fonction sort, il faut fournir un bloc de traitement, exprimé entre accolades et qui ne sera pas séparé de la liste à traiter. Le traitement effectué peut être totalement quelconque, porter sur des chaînes, des nombres ou des listes, utiliser une fonction interne à Perl ou une fonction utilisateur, etc. Dans ce bloc, l'élément en cours de traitement se trouve dans la variable interne à Perl nommée $_.

Code perl : Sélectionner tout
@l = map { $_ + 1 } @t;
et @l contiendra tous les éléments de @t augmentés de 1.

Code perl : Sélectionner tout
@l = map { ($_) x 3 } @t;
et @l contiendra tous les éléments de @t, mais dupliqués trois fois.

Code perl : Sélectionner tout
1
2
$i=0; 
@l=map { $i += $_ } @t;
et @l contiendra la somme des éléments de @t d'indice inférieur ou égal.
Si le bloc de traitement effectue des modifications sur $_, celles-ci seront répercutées sur la liste d'origine. La plus grande rigueur est donc de mise...

Code perl : Sélectionner tout
@l = map { $_ .= '+' } @t;
suffixe toutes les valeurs de @t avec un "+". Les nouvelles valeurs se trouvent aussi bien dans @t que dans @l.

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
my @mois = qw/ mars avril septembre decembre/; 
my @mois_tries = map { suffix($_); } @mois; 
  
# @mois_tries contiendra =mars= =avril= =septembre= =decembre= 
sub suffix { 
  my $argument = shift; 
  $argument = '=' . $argument . '='; 
  return $argument; 
}
À chaque élément de notre liste, un traitement sera effectué. La valeur sera encadrée du signe "=".

  • grep

C'est une fonction interne de Perl permettant de parcourir une liste et de sélectionner les éléments en fonction de critères définis. Pour les Linuxiens, c'est le principe grep !!!

La fonction parcourt l'intégralité de la liste fournie en paramètres et lui applique un traitement de sélection fourni par l'utilisateur. Elle retourne la liste des éléments qui répondent aux critères. Comme pour les fonctions sort et map, il faut fournir un bloc de traitement, exprimé entre accolades et qui ne sera pas séparé de la liste à traiter. Dans le bloc de sélection, l'élément en cours de traitement se trouve dans la variable interne à Perl nommée $_.

Code perl : Sélectionner tout
@l = grep { $_ != 0 } @t;
et @l contiendra tous les éléments non nuls de @t.

Code perl : Sélectionner tout
@l = grep { /mot-clef/ } @t;
et @l contiendra tous les éléments de @t dans lesquels "mot-clef" est présent, grâce au mécanisme des expressions rationnelles. Voici, à titre d'exemple un traitement plus complexe (bien que tout à fait artificiel, Perl ayant des mécanismes que nous allons voir bientôt qui permettent de le faire encore plus efficacement) :

Code perl : Sélectionner tout
1
2
3
4
5
6
7
8
9
# Préparation des données 
my @eleves  = qw /Valentine Chloé Sophie Olivier Jérôme Samuel/; 
my @notes   = qw/ 8 16 19 12 6 15/; 
my @indices = (0..$#eleves); 
# Fin de la préparation... 
# Relevé des notes permettant le passage en classe supérieure 
my @passage = grep { $notes[$_]>=10 } @indices; 
# liste des élèves admis 
my @passent = map { $eleves[$_] } @passage;
Cependant, ce traitement est vulnérable car le lien entre les notes et les élèves est assez lâche. Il s'agit d'un indice, une position dans le tableau. Si le tableau est trié, tout le traitement s'effondre. C'est pourquoi il existe en Perl une structure de données plus efficace pour associer des valeurs entre elles, les listes associatives.

Mis à jour le 5 mai 2005 2Eurocents djibril

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Responsable bénévole de la rubrique Perl : djibril -