TP Tableaux et listes
Informations
- La liste est la principale structure de données en Perl. Il convient de bien en connaitre les possibilités.
- Une liste est un ensemble ordonné d'éléments scalaires, tandis qu'un tableau est un ensemble indicé de scalaires.
Il s'agit en fait d'une même structure de données. La différence réside dans la vision qu'on en a et le type de
manipulations effectuées.
- Les éléments d'une même liste peuvent être de types quelconques : nombres, chaines, variable, liste ...
- Les identificateurs des listes sont précédés du symbole @,
MAIS les éléments d'une liste sont notés avec $, car ce sont des valeurs scalaires
- Les listes sont dynamiquement allouées, donc de dimension variable. Les parenthèses (...), contenant une
énumération avec des virgules, jouent le rôle de constructeur de listes.
- Exemple
$ville = "Melun";
@mesamis=("jules","julie", "julot");
@liste= ("toto", 25 , $ville , @mesamis);
# pour afficher la suite des éléments séparés par un espace
print "@liste\n";
L'exemple précédent montre qu'il n'a pas de construction directe de liste de listes en Perl.
print "$liste[3]\n" # affiche "jules"
- Création d'une liste par affectation directe de valeurs énumérées, ou indiquées par des intervalles avec
l'opérateur .. (et non pas - )
#!/usr/bin/perl
@chiffre = (0..9);
@centaine =(@chiffre, 10..99);
# va afficher la liste : 0 1 ...99
print "@centaine\n";
@alphabet = (a..z, A..Z);
# extraction d'une sous-liste :
@dix_premieres_lettres = @alphabet[0..9];
# La fonction qw() permet de s'affranchir des virgules et des quotes ou guillemets :
@mots= ("moi","toi","lui","nous","tous");
@mots= qw(moi toi lui nous tous);
- Opérateurs de manipulations d'une liste @liste
En particulier push et pop permettent de traiter la liste comme une pile.
----------------------------
--> unshift @liste, $el ; | | | | $liste[$i] | | <-- push @liste, $el;
<-- $el = shift @liste ; ---------------------------- --> $el = pop @liste ;
0 1 $i @liste-1
- Utilisation d'une liste
print "@liste"; permet d'afficher l'ensemble des éléments
$liste[1] est le second élément
$#liste est le dernier indice de la liste
$liste[$#liste] est donc son dernier élément
$taille = @liste; pour connaitre le nombre d'éléments
$der= $liste[-1] ..etc .. énumère les éléments à partir de la fin de la liste
- Parcourir une liste
La boucle foreach fait parcourir la variable $element dans la liste @liste, dans
l'ordre de ses éléments.
foreach $element (@liste) {
print "$element\n";
}
# façon classique avec une boucle for
for ($i =0 ; $i < @liste ; $i++ ) {
print "élément $i = $liste[$i]\n";
}
- Créations et manipulations de listes
- Quelques façons d'accéder aux éléments
$el = $liste[3] pour obtenir le 4ème élément
$el = pop @liste dépile et donc modifie la liste (attention !)
$el = shift @liste pour récupérer l'élément de tête, c'est-à-dire $liste[0], dépile donc la liste
($el) = @liste construit une liste contenant l'élément de tête de @liste
($a, $b, $c, @reste) = @liste affecte les 3 premiers éléments de la liste, puis la liste du reste.
- Quelques listes gérées par le système
@ARGV contient la liste des arguments passé sur la ligne de
commande après l'appel du script. (Le 1er argument passé est donc $ARGV[0]), ne pas confondre avec
$0 qui est le nom du script)
- La variable système @_ contient la liste des paramètres passés à une fonction, voir TP structures de contrôle
- Opérateurs de tri : sort, reverse
Attention : le tri est effectué par sort, en ordre ASCII ascendant !
Tester le code suivant
#!/usr/bin/perl
print "TRIS\n";
@liste = (4, 11, 24, 2, 43, 21, 16, 6);
print "Liste initiale : \n@liste\n";
@tri_alpha = sort @liste;
print "Liste triée alphabétiquement : \n@tri_alpha\n";
@tri_num = sort { $a <=> $b} @liste;
print "Liste triée numériquement (sens croissant) : \n@tri_num\n";
@tri_num = sort { $b <=> $a} @liste;
print "Liste triée numériquement (sens décroissant) : \n@tri_num\n";
@envers = reverse @liste;
print "Liste inversée : \n@envers\n\n";
- Transformations chaine de caractères <--> liste : split, join)
- split permet de construire une liste dont les éléments proviennent du découpage d'une chaine suivant les
occurrences d'un caractère choisi.
- join effectue exactement l'opération inverse, en "recollant" les éléments
d'une liste à l'aide d'un caractère séparateur pour former une seule chaine.
- exemple 1
$phrase = "Bonjour à toutes et à tous";
@mots = split " ",$phrase;
print "@mots\n";
$phrase1 = join " ", @mots;
print "$phrase1\n";
- Cas particulier important : si on utilise "" (caractère vide) comme séparateur, on agit (en séparant avec split ou
en concaténant avec join) au niveau des caractères de la chaine.
- exemple 2
$phrase = "Bonjour à toutes et à tous";
@caracteres = split "",$phrase;
print "@caracteres\n";
$phrase1 = join "", @caracteres;
print "$phrase1\n";
- Importance du contexte en Perl
- Perl a été conçu d'emblée comme un langage sensible au contexte, l'évaluation d'une même expression dépend de la
situation.
- Soit la liste @perl = qw(p e r l). Suivant qu'on l'affecte à une variable scalaire ou bien liste, @perl
ne sera pas évaluée de la même façon :
# que contiennent $a et @a sur les lignes suivantes ?
@perl = qw(p e r l);
$a = @perl; print $a,"\n";
($a) = @perl; print $a,"\n";
($a,undef,$b) = @perl; print "$a, $b\n";
@a = @perl; print @a,"\n";
- Contexte scalaire et de liste lors de la lecture dans un fichier. Rappelez les effets de :
open F, "/etc/group";
$ligne = <F>;
@lignes = <F>;
- Le contexte booléen est rencontrée par une expression placée en situation d'expression logique dans des structures
conditionnelles (if, unless) ou itératives (while).
Voici les principales règles pour l'évaluation de if ($expression) { ..
- si $expression est une chaine, le résultat est faux si elle est vide ('' ou ""), vrai sinon
- même règle pour une liste ou un hachage
- si c'est un nombre, le résultat est faux s'il est 0 (zéro), vrai sinon
- Si une affectation échoue elle est évaluée faux, comme dans ($ligne=), lorsque la fin du fichier a été atteinte
TP élémentaires
####################### exo1.pl parcours d'une liste #########################
Etudier les exemples, si nécessaire corriger et compléter
-------------------------------------------
#!/usr/bin/perl -w
@liste1 = (lundi mardi mercredi jeudi vendredi samedi dimanche);
print "affichage global :\n";
print @liste1,"\n";
print "@liste1\n";
print "taille de \@liste1 = ... \n";
print "son dernier élément est : ...\n";
print "affichage de \@liste1, élément par élément de 2 façons :\n";
print "\navec une boucle indicée for :\n";
...
print "\navec une boucle foreach :\n";
...
####################### exo2.pl manipulations de listes #####################
Commenter les instructions suivantes, et prévoir très précisément les affichages avant d'expérimenter
--------------------------------------------
#!/usr/bin/perl -w
@alpha = ('a'..'z'); @liste = (@alpha,0..9);
$el = $liste[3];
print "$el\n";
($a, $b, $c, @reste) = @liste ;
print "\$a= $a, \$b= $b, \$c =$c , \@reste= @reste\n";
($b, $a)= ($a, $b);
print "\$a= $a, \$b= $b \n";
$el = pop @liste;
print "\$el= $el, \@liste= @liste\n";
$el = shift @liste;
print "\$el= $el, \@liste= @liste\n";
print "\@alpha est la liste \n@alpha\n";
for ($i=0; $i<26 ; $i++) {
$el= pop @alpha;
unshift @alpha, $el;
}
print "\@alpha est maintenant \n@alpha\n";
##################### exo3.pl Saisie d'une liste #######################
Commenter les instructions suivantes, prévoir les affichages
--------------------------------------------
#!/usr/bin/perl -w
# pour placer la chaine saisie dans la variable $ligne
# rappel : le descripteur STDIN lié à l'entrée standard peut etre omis
$ligne = <STDIN>
# pour l'afficher à l'écran, au lieu de print STDOUT $ligne;
print $ligne;
# Pour lire une à une les lignes saisies, on utilise une construction while
# pour sortir de cette boucle : ctrl-D
while ($ligne = <>) {
# pour enlever le caractère "fin de ligne"
chomp($ligne) ;
# pour placer la ligne dans le tableau
@texte = (@texte, $ligne);
}
print "@texte\n"
################# exo4.pl créer une liste à partir d'un fichier #################
Sur un système UNIX, les comptes utilisateurs sont décrits dans un simple fichier texte /etc/passwd.
On souhaite récupérer ce fichier dans une liste. Voici la structure des enregistrements de ce fichier :
############# extrait de /etc/passwd ####################
jean:x:500:500::/home/jean:/bin/bash
thierry:x:501:501::/home/thierry:/bin/bash
admin:x:502:502::/home/admin:/bin/bash
#########################################################
- Compléter et commenter l'exécution du script
- Donner 2 façons de remettre le compte root en tête de la liste @comptes
--------------------------------------------
#!/usr/bin/perl -w
# ouvrir le fichier /etc/passwd en lecture
open P,"/etc/passwd";
# lire la première ligne, puis tout le reste
$root = ....
print $root,"\n";
@comptes = <P>;
print "\$root = $root\n";
print "2ème élément de \@comptes = ...\n";
# afficher le dernier compte :
print "Dernier compte créé dans \@comptes = ...\n";
# pour placer $root en 1ère place dans @comptes
.....
################### exo5.pl liste des comptes utilisateurs ##################
Il s'agit de rechercher les comptes utilisateurs sur un système Unix de numéros (3ème champ) supérieurs à 500 (en effet
dans beaucoup de distributions les numéros internes de comptes (uid) commencent à 500 (ceci est réglable dans
/etc/login.defs).
On demande d'afficher les champs suivants : nom, uid, répertoire personnel en complétant le
script ci-dessous)
- ouvrir le fichier /etc/passwd et extraire chaque ligne dans une boucle
- utiliser la fonction split() pour mettre les champs de chaque ligne dans une liste @champs
- comparer à 500 le champ entier contenant l'UID (c'est le 3ème champ).
- présenter une 2ème solution, en récupérant d'un coup le contenu du fichier
- Prolongement : compléter en trouvant le groupe principal et la liste des groupes secondaires
--------------------------------------------
#!/usr/bin/perl -w
$fichier="/etc/passwd";
print "Liste des comptes d'uid supérieur à 500\n";
open F, $fichier;
while (<F>) {
chomp();
@champs= ....
if ( ... >= 500) {
print " ....\n";
}
}
################## exo6.pl Construire une concaténation de listes #################
Il s'agit de récupérer et de placer dans une (seule) liste nommée @liste, toutes les lignes
contenues dans 3 fichiers. Si on n'a pas de meilleure idée, utiliser /etc/passwd, /etc/group et /etc/fstab
- construire @fichiers, la liste de ces noms de fichiers
- construire une boucle de parcours de @fichiers, dans laquelle on ouvre chaque fichier en lecture
et on empile dans @liste leur contenu
- afficher la liste @liste pour vérifier
--------------------------------------------