Apprendre Perl rapidement, 3e partie

David Bourgais

Bienvenue à nouveau dans notre dernier cours d'apprentissage rapide du langage Perl.
Nous maîtrisons maintenant les trois variables fondamentales de Perl et nous savons implémenter des boucles, des conditions, partager notre code en fonctions.
À présent, nous allons envisager ce qui fait de Perl sa robustesse, les expressions régulières, les fichiers et les modules. Bien souvent, la « légende » sur Perl veut que les expressions régulières (ou regexps, expressions rationnelles) soient particulièrement difficiles à appréhender et à lire. De même, le nombre de modules est très important et l'on ne sait lequel choisir. Mais, tout cela n'est pas la réalité de Perl et nous verrons que ces principes sont simples à apprendre. Enfin, nous verrons comment rendre notre code plus propre et plus valide.
Mais, n'oubliez pas la FAQ Perl pour plus de détails à ce préambule ainsi que le forum Perl pour nous poser toutes vos questions :). Commentez

- Titre : Apprendre Perl rapidement, 3e partie

- Auteur : David Bourgais

- Parution : 18 août 2005

- Mise à jour : 24 novembre 2019

- Licence : 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 ® 2013 GLDavid. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Expressions régulières

- II. Fichiers

- III. Modules

- IV. Comment écrire du code plus « propre » ?

- V. Le mot de la fin

I - 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 recherche 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";
}
}

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ère 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éments), 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 parler 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, quant à eux, d'exprimer la répétition d'un motif.
La FAQ (avec l'excellent Djibril) relate d'ailleurs ces divers aspects et plus encore. Nous nous contenterons d'exemples simples pour notre approche. 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 cet 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é.

II - 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 (je n’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

Cher ami,
Je suis toute émue de vous dire que j'ai
bien compris l'autre jour que vous aviez
toujours une envie folle de me faire
danser. Je garde le souvenir de votre
baiser et je voudrais bien que ce soit
une preuve que je puisse être aimée
par vous. Je suis prête à montrer mon
affection toute désintéressée et sans cal-
cul, et si vous voulez me voir ainsi
vous dévoiler, sans artifice, mon âme
toute nue, daignez me faire visite,
nous causerons et en amis franchement
je vous prouverai que je suis la femme
sincère, capable de vous offrir l'affection
la plus profonde, comme la plus étroite
amitié, en un mot : la meilleure épouse
dont vous puissiez rêver. Puisque votre
âme est libre, pensez que l'abandon où je
vis est bien long, bien dur et souvent bien
insupportable. Mon chagrin est trop
gros. Accourez bien vite et venez me le
faire oublier. À vous je veux me sou-
mettre entièrement.
Votre poupée

Les plus littéraires d'entre vous auront reconnu la fameuse lettre de George Sand à Alfred de Musset. Écrivons 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 a voulu dire à l'aide de ce code :

file2.pl

#!/usr/bin/perl

open FICHIER,"< lettre.txt" or die "Le fichier n'existe pas !";
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 contenterai de commenter ce code. Le secret de Georges Sand est de lire son véritable message toutes les deux 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 suivie 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. À la fin de notre condition, nous postincré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 >> :

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

III - 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 2e Google : 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 deux 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.

IV - 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 déboguer 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. À 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 toutes et au besoin initialisées :

better2.pl

#!/usr/bin/perl -w

use strict;

$addition=2+3;
$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;

Enfin, à l'aide du pragma Carp, ce pragma détectera pour vous vos éventuelles erreurs de syntaxe.
Ainsi, la combinaison de ces trois pragmas et flags vous permettront de repérer plus facilement vos erreurs souvent imputables à des erreurs de frappe !

V - Le mot de la fin

Hélas ! Les meilleures choses ont une fin ! Mais ce n'est qu'un au revoir. En effet, l'objectif de ces trois articles était de vous donner des bases solides pour être autonome rapidement en Perl. N'oubliez jamais que vous aurez de plus amples détails sur la FAQ Perl ainsi que sur notre forum. Alors, venez nous faire partager vos problèmes sur ce merveilleux langage pour que nous puissions les résoudre ensemble et faites-nous partager vos succès avec Perl !

@++