[PDF] Apprendre a programmer avec Perl cours de base avec exemples | Formation informatique

15  Download (0)

Texte intégral

(1)

Apprendre Perl

Qu'est ce que Perl ?

Perl est un langage interprété créé par Larry Wall qui cherchait un langage de script plus commode à utiliser que awk sous Unix. C'est pourquoi Perl est un langage particulièrement recommandé pour l'extraction de données, ne serait-ce que par la puissance de ses expressions régulières. Perl est couramment utilisé en ingénierie, plus particulièrement en bioinformatique notamment pour l'analyse génomique et post-génomique. Perl est aussi un outil très utile pour le Webmestre souhaitant réaliser des interfaces CGI. Enfin, citons l'importance de la communauté Perl, à commencer par la richesse de ses modules sur CPAN et de nombreux groupes de développeurs tels les célébrissimes mongueurs de Perl ou les Perl monks.

Enfin, vous obtiendrez toutes les actualités sur Perl (Perl 6 très bientôt !) sur le site officiel de Perl.3. Obtenir Perl

Dans ce paragraphe, nous envisagerons que vous travaillez sur des plate-formes très couramment utilisées telles Windows, Linux et MacOS X. Concernant Windows, il vous suffit de vous rendre sur la page d'ActiveState et de télécharger l'installeur de Perl. Pour Linux et les Unix en général, Perl est présent dans la quasi-majorité des distributions. Consultez

ainsi vos bases de données de paquetages.

Enfin, précisons que vous pouvez toujours télécharger sur le site officiel de Perl les sources de l'interpréteur et les installer après compilation.

4. Variables scalaires et premiers programmes

Dans cette première approche, nous écrirons des programmes simples en Perl et apprendrons à utiliser les 3 types primitifs de ce langage. Commençons donc à écrire notre premier programme nommé hello.pl :

hello.pl

#La ligne Shebang pour définir le chemin de l'interpreteur #!/usr/bin/perl

#On affiche une chaîne de caractère print "Bonjour tout le monde !";

Code on ne peut plus simple, non ;) Pour exécuter ce script, taper dans votre terminal : perl hello.pl

Et le code s'exécutera, vous affichant sur votre terminal la chaîne de caractère "Bonjour tout le monde !". Remarquez que l'écriture d'un commentaire est toujours précédée par le caractère #. Enfin, dans votre ligne shebang, il vous faudra incorporer le chemin de votre interpréteur Perl (sous Windows, vous écrirez #!C:\\Perl\\bin\\perl). Mais, voyons voir comment nous pouvons stocker des informations dans des variables. Perl est un langage non typé au regard d'autres langages comme C ou C++. Toutefois, il existe des fonctions permettant de déterminer quel type est contenu dans votre variable. Il existe 3 types de variables : les variables scalaires, les listes et les tables associatives. Une variable scalaire est la variable la plus élémentaire de Perl. Vous pourrez y stocker aussi bien des chaînes de caractères, un caractère ou un nombre. Envisageons ce code simple d'addition : ttc1.pl

(2)

print "Calcul d'un prix TTC\n";

#On initialise la valeur de notre taxe $taxe = 0.196;

#On fixe un prix hors taxe à 100 $pht = 100;

#D'où la valeur ttc

$ttc = $pht+($pht*$taxe);

print "Le prix TTC est de : $ttc.\n";

Ce code simple permet ainsi de calculer un prix codé en dur. Naturellement, nous voulons que notre code interagisse avec l'utilisateur :

ttc2.pl

#!/usr/bin/perl

print "Calcul d'un prix TTC\n";

#On initialise la valeur de notre taxe $taxe = 0.196;

#On demande de rentrer un prix hors taxe $pht = <stdin>;

#On enlève le caractère de retour chariot chomp $pht;

#D'où la valeur ttc

$ttc = $pht+($pht*$taxe);

print "Le prix TTC est de : $ttc.\n";

Pour stocker la valeur du prix hors taxe, nous avons recours au flux standard d'entrée (soit le clavier) avec la ligne $pht = <stdin>;. La fonction chomp est appelée pour supprimer le retour chariot. Ensuite vient le calcul TTC et l'affichage du résultat.

5. Listes et tableaux

Il est évident que nous n'aurons pas que des variables simples à utiliser, nous aurons sans doute à gérer des collections de variables unitaires. Les listes sont idéales pour ça. En Perl, dans une liste, vous pourrez stocker des données non plus homogènes comme en C mais hétérogènes. D'autre part l'accès à une valeur particulière d'une liste s'effectue aussi simplement qu'un accès dans un tableau en C :

tableau1.pl

#!/usr/bin/perl

print "Des listes et des boucles !\n"; #Un tableau bien hétérogène !

@tablo = (1, 2, 3, "foo", 4, "bar"); #Et une boucle une !

foreach $valeur (@tablo){

#Au passage, faisons une petite concaténation print $valeur."\t";

}

#Accès à une valeur particulière

print "\nEt si je veux la 4ème valeur du tableau ?\n"; print "La 4ème valeur du tableau est $tablo[3]\n";

Vous aurez remarqué comment nous avons initialisé notre liste. La boucle foreach nous permet à chaque tour de boucle d'affecter la variable scalaire avec la valeur en cours de la liste tablo (noté en Perl @tablo pour @rray). Enfin, l'accès à une valeur s'effectue de manière naturelle comme dans beaucoup de langages en tenant compte du fait que la première valeur d'une liste est l'élément 0.

(3)

6. Tables de hachages

Il nous reste un dernier type simple à envisager. Il s'agit des listes associatives appelées aussi tables de hachages. Ces listes répondent à un modèle clé=>valeur mais sans ordre particulier en comparaison des listes que nous avons vu précédemment. Dans notre exemple, nous allons utiliser les listes associatives pour stocker des urls :

hash.pl

#!/usr/bin/perl

print "Quelques URLs intéressantes\n";

#Les clés à gauche de la grosse flèche, les valeurs à droite de la grosse flèche

%urls = ("faq_perl"=>"http://perl.developpez.com/faq", "faq_linux"=>"http://linux.developpez.com/faq", "faq_java"=>"http://java.developpez.com/faq/java");

#Une boucle bien utile pour les listes associatives avec une chouette fonction

print "Listes des urls :\n";

#Une boucle intéressante pour récupérer les clés et les valeurs while (($cle, $valeur) = each(%urls)){

print $cle." a pour url ".$valeur."\n"; }

#Pour accéder à une valeur particulière si on connait sa clé print "On ne retient quand même que l'url de la FAQ Perl qui est ".$urls{"faq_perl"}." :)\n";

Dans ce code, nos clés sont des chaînes de caractères ainsi que les valeurs. Mais vos clés et valeurs peuvent être aussi bien des nombres. Dans notre boucle, nous récupérons la paire clé-valeur en cours grâce à la fonction each. Nous demandons ensuite d'afficher cette paire dans une chaîne concaténée. Enfin, l'accès à un élément en fonction de sa clé est simple mais répond à l'annotation suivante : $nom_de_mon_hash{ma_clé}.

II Conditions en Perl

Il peut être bien utile, dans un programme, de prendre des décisions en fonction des variables et des valeurs que vous leur donnerez. Et comme dirait l'adage : "avec des si, on mettrait Paris en bouteille !". Alors, appliquons ce proverbe dans le code suivant :

condition1.pl

#!/usr/bin/perl

print "Rentres une ville :\n"; $ville = <stdin>;

chomp $ville;

if ($ville eq "Paris") {

print $ville." rentre dans une bouteille !\n"; }

Voyons ce code. La première ligne vous est bien connue, il s'agit de la ligne shebang où nous déclarons le chemin de l'interpréteur Perl. Puis, nous affichons avec print une chaîne de caractères. La ligne suivante demande à l'utilisateur de rentrer une valeur, ici, le nom d'une ville qui sera intégré dans la variable scalaire $ville. La fonction chomp supprime le retour

chariot contenu dans la variable $ville.

Maintenant, viens notre propos. le programme se pose la question suivante : "Qu'est-ce que je fais en fonction de la valeur de $ville ?" A cela, nous lui apportons la solution : "si" la valeur de $ville est égale à Paris, alors, tu affiches la chaîne concaténée entre la valeur de

(4)

$ville et une phrase. Notez que nous mettons la solution à la condition entre une paire d'accolades ouvrantes-fermantes que l'on appelle un bloc. Mais, j'entend votre question : et si l'utilisateur ne rentre pas Paris ? Et bien, nous allons voir un autre mot-clé bien utile si un "if" est insuffisant. Il s'agit du mot else soit le "sinon" anglais. Prenons l'exemple suivant :

Condition2.pl #!/usr/bin/perl

print "Rentres un chiffre pour connaître son inverse :\n"; $nombre = <stdin>;

chomp $nombre; if($nombre == 0){

print "La division par 0 est impossible !"; }

else {

$resultat = 1/$nombre;

print "L'inverse de ".$nombre." est ".$resultat."\n"; }

Après avoir écrit notre ligne shebang, nous demandons à l'utilisateur de rentrer un nombre et nous enlevons le retour chariot. Comme nous divisons 1 par ce nombre pour obtenir l'inverse du nombre, il est évident qu'une division par 0 est impossible. Aussi, à l'aide de la paire if-else, nous allons analyser le nombre rentré. Dans notre "if", nous regardons si le nombre est égal à 0. Si c'est le cas, nous affichons une remontrance envers l'utilisateur (si, si, parfois, l'informaticien se montre sévère envers ses utilisateurs) et le programme se termine. Dans le cas contraire, le bloc else est alors invoqué : nous stockons le résultat dans la variable scalaire $resultat de la division de 1 par notre nombre $nombre. Enfin, nous affichons le résultat de cette opération dans une chaîne concaténée. Mais, Perl va encore plus loin ! En effet, ce langage propose même un mot clé contraire à "if". Il s'agit du mot clé unless (à moins que en français). Considérons le code suivant qui reprend le précédent :

Condition3.pl #!/usr/bin/perl

print "Rentres un chiffre pour connaître son inverse :\n"; $nombre = <stdin>;

chomp $nombre;

unless($nombre == 0){

$resultat = 1/$nombre;

print "L'inverse de ".$nombre." est ".$resultat."\n"; }

else {

print "La division par 0 est impossible !"; }

Notre condition se lit donc de la manière suivante : "à moins que $nombre soit égal à 0, on procède à la division. Sinon, on affiche l'erreur. Vous aurez compris la subtilité : if se contente de vérifier si la condition est vraie alors qu'unless vérifie si la condition est fausse. Bien naturellement, vous devez à chaque appel d'une condition placer un bloc (paire d'accolades ouvrantes-fermantes) à la suite de votre condition. Enfin, une dernière remarque pour les tests de comparaison. Vous aurez vu que j'ai utilisé 2 opérateurs différents pour tester une variable scalaire qui contient une chaîne de caractère et une autre qui contient un nombre. Retenez ainsi que si vous voulez comparer une égalité entre chaînes de caractères, vous devez avoir recours à l'opérateur eq (pour équivalent). Son opposé est ne (pour non-équivalent), toujours pour les chaînes de caractères. Concernant les nombres, nous retrouvons des opérateurs connus : == (pour l'égalité, attention de ne pas utiliser un

(5)

= seul !), <, > (pour les différences strictes), <=, >= (pour les différences strictes ou égales) parmi les plus usités.

2. Répéter une opération, les boucles

Dans le cours précédent, nous avons commencé à voir quelques boucles mais sans rentrer dans les détails. Maintenant, rentrons dans les détails ! Mais, à quoi sert une boucle ? Une boucle va vous aider à répéter un bloc d'instructions jusqu'à ce qu'elle satisfasse une condition. Toutefois, il existe aussi des cas où des boucles seront infinies ! C'est le cas des

IHM (Interfaces Homme-Machine).

Mais reprenons notre propos. Comme toujours, nous allons nous aider des traductions anglais => français pour comprendre une boucle. Débutons avec la boucle while. La boucle while se réalise tant que la condition n'est pas atteinte. Un petit exemple :

boucle1.pl

#!/usr/bin/perl

print "Table de multiplication de 2\n"; $i = 0;

while($i<=10){

print "$i*2 = ".($i*2)."\n"; $i++;

}

Vous aurez compris que nous allons afficher la table de multiplication de 2. Nous initialisons une variable scalaire $i à 0. Cette variable va être utilisée dans notre boucle. Notre boucle while nous dit ceci : "tant que $i est inférieur ou égal à 10, j'effectue ce que l'on me demande". la boucle while est suivie alors d'une paire d'accolades ouvrantes-fermantes contenant les instructions de la boucle (ce qu'elle doit faire). Ainsi, dans le bloc ou corps de boucle, nous demandons à afficher la valeur de $i actuelle et de la multiplier par 2. Enfin, nous incrémentons $i. L'incrémentation consiste à ajouter 1 à une valeur donnée. Il existe 2 types d'incrémentations :

 La pré-incrémentation : ++$i; où la valeur sera d'abord incrémentée.

 La post-incrémentation : $i++; où la valeur sera après incrémentée.

Enfin, il existe l'opérateur de décrémentation (--) qui se base sur les mêmes règles que l'incrémentation. Notre boucle se termine lorsque sa valeur atteint 10. En fait, comme tout langage, Perl vous autorise à écrire une boucle selon votre préférence. Par exemple, la boucle for permet de rassembler en 1 ligne l'initialisation d'une variable, sa condition et son incrémentation. La boucle for signifiant "pour", reprenons notre exemple de tout à l'heure :

boucle2.pl

#!/usr/bin/perl

print "Table de multiplication de 2\n"; for ($i=0; $i<=10; $i++){

print "$i*2 = ".($i*2)."\n"; }

Un code plus court, n'est-ce pas ? L'utilisation d'un for n'est guère différente de la boucle while. La boucle for nous dit : "Pour $i égal à 0 et tant que $i est inférieur ou égal à 10, j'incrémenterais de 1 $i et je ferais ce que l'on me dit de faire". Dans notre partie consacrée aux conditions, nous avons vu qu'il existait un opposé à if nommé unless. Comme dans la nature, il existe un opposé pour chaque élément, la boucle

(6)

while a aussi son opposé : until. Les boucles while et for se réalisent tant que la condition est vrai, la boucle until se réalise tant que sa condition est fausse. En anglais, until se traduit par "jusqu'à ce que". Voyons comment utiliser until avec notre exemple de table de multiplication :

Boucle3.pl

#!/usr/bin/perl

print "Table de multiplication de 2\n"; $i = 0;

until($i>10){

print "$i*2 = ".($i*2)."\n"; $i++;

}

Le code n'est pas si différent de notre exemple avec while. Mais la pensée est différente. Comme dans notre exemple de boucle1.pl, nous initialisons une scalaire $i à 0. mais notre boucle nous indique cette fois : "Jusqu'à ce que $i soit supérieur strictement à 10, je fais ce que l'on me dit". Le corps de la boucle ne change pas. Seule la condition a été modifiée. Mais certaines boucles sont bien utiles pour des types de variables plus évoluées comme les listes ou tables de hachages. Ainsi, la boucle foreach est très pratique pour parcourir les éléments d'une liste. Cependant elle peut aussi manipuler aisément une table de hachage : Boucle4.pl

#!/usr/bin/perl

@liste = (0,1,2,3,4,5,6,7,8,9,10); print "Table de multiplication de 2\n"; foreach $i (@liste){

print "$i*2 = ".($i*2)."\n"; }

Nous avons ainsi initialisé une liste avec une série de chiffres. Puis la boucle indique "Pour chaque élément noté $i de la liste @liste (écrite entre parenthèse), je fais ce que l'on me dit". Le corps de la boucle multiplie ainsi l'élément en cours par 2 et affiche le résultat.

3. Variables spéciales de Perl

Perl contient quelques variables réservées qui sont bien utiles notamment pour manipuler les paramètres d'appels d'un script, rapporter une erreur ou connaître son environnement. Loin de nous est l'objectif de dresser une liste exhaustive de ces différentes variables, nous nous contenterons de vous citer les plus utiles. Commençons par quelques variables scalaires spéciales. Savez-vous qu'il existe une variable scalaire par défaut ? Celle ci est noté $_. Elle contient tout ce qui est en cours d'une boucle ou elle est la variable par défaut de nombreuses fonctions.

Special1.pl

#!/usr/bin/perl

@liste = (0,1,2,3,4,5,6,7,8,9,10); print "Table de multiplication de 2\n"; foreach (@liste){

print "$_*2 = ".($_*2)."\n"; }

(7)

Vous connaissez ce code, il s'agit de l'affichage de la table de multiplication de 2 à l'aide d'une boucle foreach. Mais vous me direz qu'il manque une variable. Pas du tout ! Dans notre ligne où nous décrivons notre boucle foreach, la variable spéciale $_ peut être écrite explicitement sinon elle est appelé implicitement par le code. Notre code aurait pû s'écrire de la manière suivante avec le même résultat :

Special2.pl

#!/usr/bin/perl

@liste = (0,1,2,3,4,5,6,7,8,9,10); print "Table de multiplication de 2\n"; foreach $_ (@liste){

print "$_*2 = ".($_*2)."\n"; }

Il est aussi parfois bien utile de rapporter une erreur. La variable $! sert ainsi à enregistrer l'état de votre erreur :

special3.pl

#!/usr/bin/perl

print "Rentres un nom de fichier :\n"; $fichier = <stdin>;

chomp $fichier; if (-f $fichier){

print "$fichier existe.\n"; }

else {

print "$!\n"; }

A l'aide de ce code, nous demandons au script de vérifier si le fichier dont le nom est rentré par l'utilisateur existe. Si c'est le cas (avec l'option -f d'un if, nous testons l'existence d'un fichier dont le nom est contenu dans une variable scalaire), le script affiche que le fichier existe. Dans le cas contraire, nous affichons le contenu de notre erreur. Si vous rentrez un nom de fichier qui n'existe pas, $! contiendra alors la valeur :

No such file or directory

Il existe aussi des listes spéciales à Perl. Aussi, vous savez que de nombreux programmes ont besoin de paramètres pour pouvoir s'exécuter. Un exemple sur les machines Unix est que certaines commandes vous affichent de l'aide lorsqu'elles n'ont pas d'arguments ou que ceux-ci sont inexacts. Aussi, comment pouvons-nous tester l'existence de paramètres pour un programme Perl. Tous les paramètres invoqués par un script Perl sont ainsi contenu dans un tableau spécial, le tableau @ARGV. Sa manipulation est identique à tous les tableaux que vous créerez en Perl :

Special4.pl #!/usr/bin/perl foreach (@ARGV){ print $_; }

Dans ce simple code, nous voulons afficher la liste des paramètres passés à notre programme. Comment passe t'on un argument ? Quand vous appelez votre script, il suffit d'écrire à sa suite les arguments :

(8)

perl special4.pl toto tata tutu

Ainsi, notre programme special4.pl vous affichera toto, tata puis tutu. Ceci est particulièrement utile quand vous passez à votre programme un nom de fichier :

special5.pl

#!/usr/bin/perl

foreach $file (@ARGV){ if (-f $file){

print "OK, $file existe.\n"; }

else {

print "$file : $!\n"; }

}

Enfin, il existe des listes associatives ou tables de hachages spéciales. Nous citerons ainsi %ENV qui contient ainsi tous les renseignements sur votre système :

Special6.pl

#!/usr/bin/perl

print "Liste des informations de votre système :\n"; while (($cle, $valeur) = each (%ENV)){

print "$cle a comme valeur $valeur.\n"; }

Naturellement, cette table de hachage se manipule comme toute bonne table de hachage : special7.pl

#!/usr/bin/perl

print "Votre processeur est un $ENV{'PROCESSOR_IDENTIFIER'} :\n"; 4. Ecrire des fonctions

Pour le moment, nous nous sommes contentés d'écrire du code monolithique soit qui tient en un seul bloc. Cependant, dans les langages modernes (dont Perl), il est souvent bien utile de compartimenter notre code en des blocs qui auront des tâches bien spécifiques à remplir. Ces blocs sont appelés des fonctions. Ces fonctions peuvent prendre ainsi des arguments, traiter ensuite ces éventuels arguments et peuvent aussi rendre un résultat. Moralité, les informaticiens répondent à l'adage "Diviser pour mieux régner". L'écriture d'une fonction n'est guère compliquée. Vous devez ainsi déclarer votre fonction précédée du mot clé sub (pour sub-function, en anglais sous-fonction), suivi ensuite d'une paire ouvrante-fermante d'accolades. Celles-ci définiront le corps de la fonction soit les instructions que votre fonction devra traiter. Prenons un exemple simple :

fonction1.pl

#!/usr/bin/perl

sub fonction{

print "La fonction est appelée.\n"; }

(9)

#Corps principal de notre script print "Début de notre script.\n"; fonction();

print "C'est tout pour aujourd'hui.\n";

Ainsi, notre script débutera toujours par son corps principal. En l'occurence, notre code affichera d'abord la chaîne de caractères "Début de notre script.\n". Puis, nous appelons notre fonction par son nom suivi d'une paire de parenthèses. Ces parenthèses contiendront les arguments passés à notre fonction. Ici, nous avons rien à transmettre donc, nous laissons notre paire de parenthèses vide. La fonction ainsi appelé va donc faire ce pourquoi elle a été crée : afficher la chaîne de caractères "La fonction est appelée.\n". Enfin, le corps principal de notre fonction reprend la main et affiche la dernière chaîne "C'est tout pour aujourd'hui.\n".

Nous avons vu que nous pouvons transmettre des arguments à une fonction via la paire de parenthèses invoquées lors de l'appel. Ainsi, prenons l'exemple suivant :

fonction2.pl

#!/usr/bin/perl

sub inverse{

if ($_[0] == 0){

print "Division par 0 impossible !\n"; }

else {

$resultat = 1/$_[0];

print "L'inverse de $_[0] est $resultat.\n"; }

}

print "De quel nombre voulez-vous avoir l'inverse ?\n"; $nombre = <stdin>;

chomp $nombre; inverse($nombre);

Dans ce code, nous demandons à l'utilisateur de rentrer un nombre. Celui-ci est stocké dans la variable scalaire $nombre. Puis, cette scalaire $nombre sera transmise à la fonction inverse dans la paire de parenthèses. venons-en à notre fonction inverse. Notre nombre est contenu dans une variable nommé $_[0] qui est testé dans un if pour vérifier si, bien entendu, ce nombre n'est pas égal à 0. Et oui, nous avons une nouvelle variable spéciale ! Cette variable est en réalité le tableau @_ qui contient tous les paramètres transmis à une fonction. Le tableau spécial @_ peut aussi bien contenir des variables scalaires, des nombres, des chaînes de caractères et même des tableaux et des tables de hachages. Vous pouvez tout transmettre à une fonction. Dans le cas où notre valeur est égale à 0, la fonction répond par un message d'erreur. Dans le cas contraire, elle procède au calcul de l'inverse et

renvoie le résultat.

Enfin, nous avons vu qu'il était tout à fait possible qu'une fonction renvoie un résultat. Une fonction peut très bien renvoyer un résultat qui soit une variable scalaire, une liste ou une table de hachage. Reprenons notre calcul d'inverse :

fonction3.pl

#!/usr/bin/perl

sub inverse{

if ($_[0] == 0){

print "Division par 0 impossible !\n"; }

(10)

else { $resultat = 1/$_[0]; return $resultat; } }

print "De quel nombre voulez-vous avoir l'inverse ?\n"; $nombre = <stdin>;

chomp $nombre;

$reponse = inverse($nombre);

print "L'inverse de $nombre est $reponse.\n";

Dans le corps principal de notre script, nous appelons certes notre fonction mais vous remarquerez que nous demandons à ce que le résultat de cette fonction soit contenu dans la variable scalaire $reponse. Notre fonction va donc tester la valeur de son argument (est-elle égale à 0 ou non) et dans le cas où celui-ci n'est pas égal à 0, la fonction procède au calcul de l'inverse. Ce calcul est contenu dans la variable $resultat. Puis, la fonction va retourner la valeur de $resultat au corps principal de notre script par l'intermédiaire du mot clé return suivi de la variable à retourner (return se traduit par retourne en anglais). Notre script reprend la main avec la valeur $reponse égale au calcul de l'inverse du nombre demandé à l'utilisateur et nous affichons le résultat. Cette manière d'écrire son code rend plus simple la lecture et permet aussi au programmeur de réutiliser des fonctions suffisamment génériques dans d'autres codes. D'où un intérêt dans la simplification de résolution d'un problème et une portabilité des solutions apportées.

III Expressions régulières

Les expressions régulières sont devenues incontournables dans la programmation moderne.

Il s'agit de motifs, d'une suite de caractères que l'on souhaite repérer dans un texte. Elles

sont à la base des moteurs de recherches actuels et sont très utiles dans des domaines

d'ingénierie comme la bioinformatique.

Mais comment utiliser une expression régulière ? prenons le code suivant :

regexp1.pl

#!/usr/bin/perl

@tablo = ("Barney", "Homer", "Marge", "Bart", "Lisa", "Maggie", "Moe", "Flanders");

print "Quel nom voulez-vous repérer ?\n";

$nom = <stdin>;

chomp $nom;

for ($i=0; $i<@tablo; $i++){

if($tablo[$i] =~ /$nom/){

print "$nom est en position $i\n";

}

(11)

Si vous avez bien suivi les cours précédents (les avez-vous lu ???? :) ), le code avant la boucle

ne devrait pas vous poser de problèmes. Bon, d'accord, j'explique : nous initialisons un

tableau avec des chaînes de caractères contenant des noms. Puis, le programme Perl vous

demandera de rentrer un nom. Cette chaîne sera stockée dans la variable $nom et le

caractères d'échappement sera supprimé pour éviter tout biais. Puis vient notre boucle.

Dans celle-ci, nous parcourons notre tableau pour vérifier si le nom est présent et si oui, à

quelle place. Au passage, vous aurez remarqué que pour obtenir la taille d'un tableau (c'est à

dire son nombre d'élément), il suffit d'appeler la variable @tablo qui donne le nombre

d'éléments. Et comment repérer ce nom ? Grâce aux expressions régulières bien sûr !

Regardons la construction de notre condition if : nous examinons la valeur du tableau en

cours. Vous pouvez voir à côté un nouvel opérateur =~ : il s'agit de l'opérateur de liaison.

C'est lui qui va rendre la comparaison possible entre votre valeur en cours et votre

expression régulière. Enfin, nous avons notre expression régulière à proprement parlée

comprise entre une paire de slaches (//). Dans le cas où notre expression régulière

correspond à la valeur en cours, le résultat s'affiche.

Quel nom voulez-vous repérer ?

Homer

Homer est en position 1

Naturellement, l'on peut affiner sa recherche, notamment en passant par les caractères

spéciaux et les quantificateurs. Les caractères spéciaux sont des caractères dits jokers qui

remplacent une série de caractères d'une même catégorie. Les quantificateurs vous

permettront, quand à eux, d'exprimer la répétition d'un motif.

La Image non disponible FAQ (avec l'excellent Djibril) relate d'ailleurs ces divers aspects et

plus encore. Nous nous contenterons pour notre approche à des exemples simples. Par

exemple, considérons le code ci-dessous :

regexp2.pl

#!/usr/bin/perl

$chaine = "L'âge du capitaine est de 28 ans.";

if($chaine =~ /\d+/){

print "L'âge est $& ans\n";

}

Dans cette exemple, nous voulons récupérer le nombre qui est contenu dans une chaîne de

caractères. Ainsi, dans notre test, notre expression régulière contient le caractère spécial \d

qui sert à récupérer n'importe quel chiffre. Le quantificateur + qui y est adjoint dit à notre

expression régulière qu'un chiffre est répété au moins 1 fois. Ainsi, si notre chaîne est bien

analysée, le programme écrira donc la phrase "L'âge du capitaine est 28 ans" en utilisant la

variable $& qui contient le motif repéré.

(12)

2. Fichiers

Jusqu'à présent, nous nous sommes contentés de lire et d'écrire sur la sortie standard soit

l'écran de nos ordinateurs. Maintenant, dans l'informatique de tous les jours, nos

programmes lisent et écrivent dans des fichiers. Pourquoi pas nos programmes Perl ?

Pour pouvoir lire et écrire dans des fichiers, Perl a besoin de flux de fichiers aussi appelés

handle. Rassurez-vous, lire et écrire des fichiers en Perl est bien plus simple qu'en Java par

exemple (j'ai jamais pu retenir les différents objets à initialiser pour lire et écrire, honte de

l'auteur !). Commençons déjà par lire un fichier. Considérons que nous avons sur notre

ordinateur un fichier nommé lettre.txt :

Lettre.txt

Les plus littéraires d'entre vous auront reconnu la fameuse lettre de George Sand à Alfred de

Musset. Ecrivons un premier programme pour afficher tout ce texte sur notre sortie

standard :

file1.pl

#!/usr/bin/perl

open FICHIER,"< lettre.txt" or die "Le fichier n'existe pas !";

while ($ligne = <FICHIER>){

print $ligne;

}

close FICHIER;

Code très simple, non ? Dans notre première ligne, nous ouvrons un flux qui s'appelle

FICHIER, mais vous êtes libre du nom que vous lui affecterez. Puis, après la virgule, dans la

chaîne de caractères, nous indiquons à Perl le mode opté pour notre flux : lecture ou

écriture ? Les amateurs d'Unix ne seront pas trop lésés : un chevron < indique une lecture et

bien sûr, son opposé, > indique l'écriture. Revenons à notre code. La suite de la chaîne de

caractères est composée du chemin vers votre fichier à exploiter. Après notre chaîne pour

définir notre flux, nous voyons un traitement d'erreur : si le flux ne venait à ne pas être créé

(le fichier n'existe pas, par exemple), le programme s'arrête (meurt) en écrivant un message

d'avertissement. Ensuite, vient une boucle. Dans cette boucle, la ligne en cours est affectée

à la variable scalaire $ligne. Mais rien ne vous empêche aussi de recourir à la variable

scalaire par défaut de Perl $_ en écrivant while(<FICHIER>). Dans cette boucle, nous

affichons sur la sortie standard le contenu de notre variable $ligne. Enfin, au sortir de la

boucle, il est recommandé de toujours fermer son flux à l'aide de la commande close.

Comme dit plus haut, rien ne vous empêche de traiter votre ligne en cours et d'écrire un

fichier. Décodons ce que George Sand à voulu dire à l'aide de ce code :

file2.pl

#!/usr/bin/perl

(13)

open WRITER,"> decode.txt" or die "Le fichier ne peut être édité !\n";

$i=0;

while ($ligne = <FICHIER>){

if($i%2){

print WRITER $ligne;

}

$i++;

}

close FICHIER;

close WRITER;

open FICHIER,"< decode.txt" or die "Le fichier n'existe pas !";

while ($ligne = <FICHIER>){

print $ligne;

}

close FICHIER;

Je vous laisse la surprise du résultat, je me contenterais de commenter ce code. Le secret de

Georges Sand est de lire son véritable message toutes les 2 lignes. Donc, il faut lire les lignes

qui sont des multiples de 2. Ainsi, nous ouvrons un premier flux pour la lecture de notre

fichier lettre.txt. Puis, nous ouvrons un deuxième flux pour l'écriture d'un fichier nommé

decode.txt. Nous initialisons aussi une variable scalaire $i à 0. Notre boucle récupère bien

sûr chaque ligne du fichier d'entrée. Pour chacune de ces lignes (la première étant la ligne 0

puis la ligne 1, etc, etc...), nous testons la valeur en cours de $i. L'opérateur % signifie

modulo. En fait, nous testons avec cet opérateur si le reste de la division de $i par 2 est égal

à 0. Cela revient à tester si notre valeur $i est paire ou non. Si cette variable est paire, nous

écrivons dans notre nouveau fichier decode.txt la ligne en cours. Notez d'ailleurs que

l'instruction print est suivi du nom du flux puis de la chaîne à afficher. Dans le cas où le flux

est absent, Perl considère que print devra écrire sur la sortie standard. A la fin de notre

condition, nous post-incrémentons $i de 1 pour passer à la ligne suivante. Après notre

boucle, nous fermons nos flux de fichiers. La deuxième partie de notre code consiste à lire

notre fichier decode.txt. Si vous avez bien suivi, ce code ne devrait plus vous poser de

problème et je vous laisse méditer sur la réponse de George Sand :D.

Une remarque toutefois pour l'écriture des fichiers. Si l'on suppose que dans notre code

vous ayez déjà un fichier decode.txt et que vous exécutez le programme file2.pl, le fichier

decode.txt sera écrasé par le résultat de notre programme. Dans le cas où vous souhaitez

juste écrire à la suite d'un fichier sans pour autant écraser ce qu'il y avait auparavant, je vous

recommande l'utilisation des doubles chevrons >> :

(14)

open WRITER,">> decode.txt" or die "Le fichier ne peut être édité !\n";

3. Modules

Les modules sont l'équivalent des bibliothèques pour d'autres langages. Beaucoup de

développeurs Perl ont ainsi contribué à l'émergence de Perl en écrivant de tels modules

pour nous simplifier la vie. On trouve ainsi des modules pour interagir avec les SGBDR

actuels, pour écrire du HTML, pour analyser aussi bien du HTML que du XML et pour traiter

des images.

Ici, nous n'allons pas vous citer tous les modules existants, la vie de l'auteur ne suffirait pas !

Au contraire, nous allons vous indiquer le site que tout développeur Perl considère comme

étant son 2ème Google : Image non disponible CPAN. CPAN est en fait le lieu de

rassemblement de tout développeur Perl. C'est une base gigantesque en scripts mais aussi

en modules Perl. Pratiquement toutes les réponses sont dans CPAN. Ainsi, si vous souhaitez

chercher un module bien particulier, CPAN met à votre disposition un moteur de recherche.

La FAQ explique aussi comment installer les modules et utiliser 2 modules majoritaires que

sont les modules MySQL et CPAN. Mais elle explique aussi que vous pouvez écrire vos

propres modules Perl et même les proposer auprès de CPAN.

4. Comment écrire du code plus "propre" ?

Maintenant, vous voilà presque de véritables codeurs Perl. Mais, au cours de l'écriture de

vos codes, vous souhaitez rapidement détecter les erreurs et debugger plus efficacement

votre code source. Commençons par des avertissements :

better.pl

#!/usr/bin/perl -w

$addition=2+3;

$chaine = "six";

$addition = $addition+$chaine;

Dans notre ligne shebang, nous avons ajouté un flag (ou drapeau) noté -w (pour warnings).

Vous convenez qu'il est illogique d'ajouter à une valeur une chaîne de caractères. Pour un

calcul, cela n'a aucun sens. A l'aide de ce flag, Perl vous avertit ainsi que votre opération

n'est pas valide :

erreur

Argument "six" isn't numeric in addition (+) at toto.pl line 5.

Allons encore plus loin. Maintenant, nous voulons que nos variables soient déclarées une

bonne fois pour toute et au besoin initialisées :

better2.pl#!/usr/bin/perl -w

use strict;

(15)

$chaine = "six";

#Il ne sert plus à rien d'écrire cette chaîne qui est une hérésie !

#$addition = $addition+$chaine;

Exécutez ce source, Perl ne semble guère apprécier !

Global symbol "$addition" requires explicit package name at toto.pl line 5.

Global symbol "$chaine" requires explicit package name at toto.pl line 6.

Global symbol "$addition" requires explicit package name at toto.pl line 7.

Global symbol "$addition" requires explicit package name at toto.pl line 7.

Global symbol "$chaine" requires explicit package name at toto.pl line 7.

Execution of toto.pl aborted due to compilation errors.

En effet, avec le pragma strict, vous devez déclarer vos variables avec le mot clé my. Avec ce

mot clé, Perl évite ainsi de faire des confusions entre vos variables de scripts et d'éventuelles

variables de fonctions ou internes aux boucles. Ainsi, notre code corrigé s'écrira :

Better3.pl

#!/usr/bin/perl -w

use strict;

my $addition=2+3;

my $chaine = "six";

#Il ne sert plus à rien d'écrire cette chaîne qui est une hérésie !

#$addition = $addition+$chaine;

Figure

Updating...

Références