Programmation Perl/Version imprimable

Ceci est la version imprimable de Programmation Perl.
  • Si vous imprimez cette page, choisissez « Aperçu avant impression » dans votre navigateur, ou cliquez sur le lien Version imprimable dans la boîte à outils, vous verrez cette page sans ce message, ni éléments de navigation sur la gauche ou en haut.
  • Cliquez sur Rafraîchir cette page pour obtenir la dernière version du wikilivre.
  • Pour plus d'informations sur les version imprimables, y compris la manière d'obtenir une version PDF, vous pouvez lire l'article Versions imprimables.


Programmation Perl

Une version à jour et éditable de ce livre est disponible sur Wikilivres,
une bibliothèque de livres pédagogiques, à l'URL :
https://fr.wikibooks.org/wiki/Programmation_Perl

Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la Licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans Texte de dernière page de couverture. Une copie de cette licence est incluse dans l'annexe nommée « Licence de documentation libre GNU ».

Introduction

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle

<< Retour au sommaire

Perl (Practical Extraction and Report Language ou langage pratique d'extraction et de génération de rapports) est un langage de programmation créé par Larry Wall en 1987 et reprenant des fonctionnalités du langage C et des langages de scripts sed, awk et shell (sh). Bien que son nom soit l'objet de plusieurs acronymes on l'utilise généralement avec un P majuscule pour désigner le langage et un p minuscule en parlant de l'interpréteur. « Seul perl analyse correctement Perl ».

Origines et implémentation modifier

Perl est né du besoin de disposer d'un langage optimisé pour l'extraction d'informations de fichiers textes et la génération de rapports.

Une de ses devises est « There Is More Than One Way To Do It (TIMTOWTDI) » qui pourrait se traduire par « Il y a plus d'une façon de le faire ». Ce qui est un point fort d'après les adeptes puisque chacun peut écrire du code comme il l'entend. Bien entendu, ceci peut être vu comme un point faible puisque ça donne lieu à différents styles très différents de code et pour le lecteur qui lira des codes de différents programmeurs, il faut s'adapter.

Une autre est « Perl : le couteau suisse des langages de programmation ». Sa souplesse autorise l'emploi de plusieurs modèles de programmation : programmation procédurale, programmation fonctionnelle et POO---bien que les puristes de ce dernier ne considèrent pas Perl comme en faisant partie, son objectif est de s'adapter aux goûts du programmeur plutôt qu'une architecture stricte du langage. Perl est souvent considéré comme le langage de script par définition et a été qualifié de "ciment assurant la cohésion du web", étant un des langages CGI les plus populaires.

Un autre point qui ne fait pas consensus est le nombre de raccourcis dans le langage Perl pour écrire du code plus rapidement et de façon élégante. Mais l'usage trop courant de ces raccourcis rend le code plus difficile à appréhender pour un non averti.

Perl est un logiciel libre, distribué sous licence artistique et GPL. Perl est porté sur la plupart des systèmes d'exploitation mais excelle particulièrement en environnement UNIX et ses dérivés; il gagne aussi en popularité sous Microsoft Windows. Un exemple du champ d'action de Perl est son utilisation comme script CGI pour faire tourner Wikipédia jusqu'en janvier 2002.

Une immense collection de modules Perl d'utilisation libre, allant des mathématiques avancés aux connexions aux bases de données, en passant par les réseaux et bien davantage encore, peuvent être téléchargés depuis un réseau de sites appelé CPAN.

Bien que Perl profite de la plupart des facilités d'un langage interprété, à proprement parler il n'interprète et n'exécute pas le code source une ligne à la fois. En fait, Perl compile d'abord le programme entier dans un bytecode intermédiaire (assez dans l'esprit du code objet Java), l'optimisant au passage, et exécute alors ce bytecode. Il est possible de compiler un programme Perl en bytecode pour s'épargner les phases de compilation lors d'exécutions futures, bien que l'« interpréteur » est toujours requis pour exécuter ce code.

Perl 6 est en cours de développement. Il tournera dans la machine virtuelle Parrot.

Ce qu'il faut savoir sur ce livre modifier

Le but modifier

Le but de ce livre est de fournir une documentation suffisante pour maîtriser en grande partie le langage Perl dans sa version 5 (à partir de la version 5.10). Il présentera la base du langage en premier lieu, puis quelques aspects avancés entrecoupés de tutoriels et travaux pratiques divers afin d'entraîner le lecteur à l'écriture de scripts divers. Le tout sera agrémenté d'un nombre conséquent d'exemples, de bonnes pratiques à adopter, d'indications sur les bibliothèques logicielles les plus utiles, et toute information qui nous semblera pertinente.

Les exemples présentés modifier

Nous utiliserons la version 5.14 de l'interpréteur perl.

Tout code présenté ici commencera par ces 4 lignes qui seront présentées dans les bases du langage :

#!/usr/bin/env perl
use strict;
use warnings;
use v5.14;

Je ne les répèterai pas pour ne pas alourdir chaque exemple (qui seront nombreux), si vous souhaitez exécuter le code présent dans ce livre n'oubliez pas de les écrire en premier dans votre code. Cela fait partie des bonnes pratiques de programmation en Perl.

Pour les débutants modifier

Vous voulez apprendre à programmer des applications, et ceci est votre premier livre sur le sujet. Voici quelques informations de base sur la programmation.

Votre premier éditeur de texte modifier

Tout d'abord, pour programmer il faut un éditeur de texte. N'importe-quel éditeur de texte suffit pour programmer, cependant il est conseillé que votre éditeur de texte ait au moins la coloration syntaxique du langage que vous apprenez (ici Perl). Il en existe un nombre assez conséquent, mais voici quelques pistes :

  • avec une interface graphique
  • gedit : simple, possède une coloration syntaxique, suffisant, existe sous Linux
  • Notepad++ : simple, pour les gens sur Windows
  • sans interface graphique (en ligne de commande sous GNU/Linux ou Unix)
  • vim : très puissant mais nécessite un petit temps d'adaptation
  • emacs : comme vim

Comment bien apprendre modifier

Vous allez apprendre à programmer dans un certain langage de programmation. Avant de commencer, il faut savoir que cela va prendre du temps, et qu'il ne faut pas se précipiter. Lisez bien chaque exemple, essayer de modifier tous les bouts de code présentés en les complexifiant de plus en plus, essayez de faire tous les exercices et prenez le temps qu'il vous faut. Ce n'est pas une course, passez deux à trois heures maximum à apprendre par jour, c'est amplement suffisant.


Bases du langage

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Bonjour ! modifier

L'un des plus petits programmes possible en langage Perl est :

#!/usr/bin/env perl
use strict;
use warnings;
use v5.14;

say "Bonjour !";

(Les numéros de lignes ont été ajoutés pour la lisibilité, mais ne font pas partie du programme.)

Ce programme a pour seul but d'afficher le texte « Bonjour ! » suivi d'un retour à la ligne. Voici la description de chaque ligne qui le compose :

#!/usr/bin/env perl

Ceci s'appelle un shebang et est destiné à déterminer quel est l'interpréteur à utiliser pour comprendre les instructions qui suivent.

use strict;
use warnings;
use v5.14;

Ceci décrit respectivement les conventions d'écriture (strict), l'affichage de message d'avertissement (warnings), ainsi que l'utilisation d'une certaine version de l'interpréteur Perl. Maintenant que vous savez ceci, vous comprenez que les 4 premières lignes ne sont pas toujours strictement nécessaires mais que cela fait partie des bonnes pratiques de les écrire. Pour cela, comme dit dans l'introduction, il faut inclure ces 4 lignes en début de chaque programme que vous écrirez.

say "Bonjour !";

Affiche simplement la chaîne de caractères Bonjour !. Le mot clé réservé say permet d'afficher une chaîne de caractères suivit par un retour à la ligne.

À noter qu'à l'exception de la première ligne, chaque autre ligne se termine par un point virgule, désignant comme dans beaucoup d'autres langages de programmation la fin d'une instruction.

Compilation modifier

Pour pouvoir exécuter un programme Perl, il faut soit l'exécuter via la commande perl fichier_perl.pl soit on rajoute le shebang (vu plus haut), on rend le fichier exécutable chmod +x fichier_perl.pl puis on l'exécute ./fichier_perl.pl.

Éléments de syntaxe modifier

Commentaires modifier

Sur une ligne modifier

# ceci est un commentaire

Les commentaires se font sur une ligne et commencent à partir du caractère dièse # .

Sur plusieurs lignes : POD modifier

Écrire un commentaire sur une ligne c'est pratique lorsque nous avons très peu de commentaire à faire, mais nous avons parfois besoin de beaucoup plus d'une ligne pour écrire une explication un peu plus longue. Dans ce cas, il est possible d'utiliser un mécanisme intégré à Perl qui a été conçu pour que les scripts comportent directement leur propre documentation : POD (Plain Old Documentation - Bonne Vieille Documentation). Avec ce système, nous allons écrire notre propre documentation directement au milieu de nos lignes de code (comme il se fait de nos jours dans un bon nombre d'autres langages).

À savoir que tout code est commenté de cette manière sur le CPAN, le plus gros rassemblement de modules Perl. Nous reverrons le CPAN et les modules qui permettent de réutiliser du code déjà écrit (même par d'autres développeurs) plus tard.

Un exemple simple d'instructions POD (se trouve au milieu d'un code) :

=pod

Toujours commencer par =pod puis un saut de ligne.

J'écris ici un commentaire
qui s'étend sur plusieurs
lignes.

Après un saut de ligne, le début d'un 
autre paragraphe.

=cut

La structure est très simple, on commence par =pod, un saut de ligne, on écrit nos commentaires, un saut de ligne et on termine par =cut. Cela permet d'écrire de la documentation très facilement, puis de la convertir en html pour la voir dans un navigateur web par exemple.

La directive =pod déclare le début du commentaire, =cut la fin (et donc la reprise de l'interprétation du code Perl).

Sachez qu'il est possible de faire de la documentation bien plus structurée que simplement plusieurs paragraphes séparés par un saut de ligne, afin qu'un formateur de code POD puisse le transformer en fichier LaTeX ou HTML plus facilement compréhensible. Cependant pour ne pas alourdir ce livre, je vous renvoie sur quelques tutoriels dont les liens se trouvent dans les ressources.

instructions modifier

Chaque instruction est séparée par un point virgule (;). Les blocs d'instructions commencent par une accolade ouvrante ({) et se terminent par une accolade fermante (}). Contrairement au langage C, les instructions ne sont pas toujours dans ces blocs, nous verrons ça plus tard.

my $variable = 42 ;
# plusieurs instructions sur une ligne
my $a = 2; print "hello" ; print "\n"; $a = 5;
# bloc d'instruction
{
        say "coucou"; # instruction dans un bloc
}

déclaration de variables modifier

portée $variable;

portée des variables modifier

Le mot clé my désigne une portée locale, c'est à dire limitée à un bloc d'instructions. Le mot clé our désigne une portée globale, c'est à dire visible partout dans le fichier (dans les différentes fonctions, par exemple). Lorsqu'une variable est visible, elle est lisible et modifiable.


Types de base

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Les types modifier

En Perl il n'y a que 3 types de base. Ils sont reconnaissables à leur sigil, qui est un caractère avant le nom de la variable ($, @, %). Nous parlerons également de références qui est un moyen, comme son nom l'indique, de faire référence à une autre variable (proche de la notion de pointeurs en C).

Scalaire modifier

Sigil : $ . Le type scalaire est un type qui peut garder en mémoire diverses informations. Exemple :

my $a = 42 ; # ceci est un entier
my $b = 2.5 ; # ceci est un décimal
my $c = "Une chaîne de caractères";
my $d = 'Une autre chaîne';

Référence sur scalaire modifier

my $refa = \$a; # on référence la variable $a

Déférencement sur scalaire modifier

my $a = $$refa; # $a vaut la valeur de la variable référencée par $refa

Référence modifier

Une référence est un scalaire qui permet d'accéder à l'adresse mémoire où est stockée un autre scalaire, un tableau, un tableau associatif ou même une fonction. C'est très utilisé pour passer des tableaux en paramètre d'une fonction, ou tout autre élément que nous souhaiterions modifier sans passer par des copies de leurs valeurs. Nous allons voir par la suite comment les manipuler.

Tableau modifier

Sigil : @ . Un tableau permet de stocker une liste. Une liste permet de stocker plusieurs éléments (des scalaires, des références). Une liste peut également être stockée dans un tableau associatif.

Voyons d'abord les tableaux :

my @tableau1 = ( "chaine1", "chaine2", "chaine3" ); # tableau de mots
my @tableau2 = ( @tableau1, "chaine4" ); # tableau de mots composé des mots de tableau1 + "chaine4"

accéder à une valeur d'un tableau modifier

Il suffit d'utiliser les crochets [] et d'indiquer l'indice de l'élément recherché. À retenir : la numérotation commence à 0.

my $chaine = $tableau[2]; # accès au troisième élément du tableau @tableau

Référence sur tableau modifier

my $ref = [ "chaine1", "chaine2", "chaine3" ]; # référence à une liste nouvellement créée (sans passer par un tableau)
my $ref2 = \@liste; # référence d'un tableau précédemment créé

Déférencement de tableau modifier

my @tableau = @$ref; # déférencement d'un tableau

Tableau associatif modifier

Sigil : % . Un tableau associatif (ou table de hashage) est un type qui permet d'associer un scalaire à un autre.

my %tableau = ( cle1 => "valeur1", cle2 => "valeur2" );

accéder à une valeur du tableau modifier

my $chaine = $tableau{"clé_chaine"};

Référence sur tableau associatif modifier

my $ref = \%tableau; # référencement

Déférencement de tableau associatif modifier

my %tableau = %$ref; # déférencement d'un tableau associatif

Contexte modifier

En Perl, la notion de contexte est importante et très utile. Suivant comment vous faites appel à la une variable, suivant l'opérateur que vous utilisez ou l'expression utilisée, vous faites appel à un contexte particulier. Petite présentation des contextes les plus utilisés.

Contexte numérique modifier

L'expression évaluée est considérée comme un nombre. Les opérateurs utilisés traiteront les scalaires comme des nombres, ainsi la chaîne de caractères 01.50 sera interprétée comme le nombre 1.5. Dans ce contexte, les listes et les tableaux renvoient leur nombre d'éléments. Dans ce contexte, la valeur renvoyée par un élément de type undef est 0.

Contexte (scalaire) de chaîne modifier

Un nombre est considéré comme une chaîne, et nous pouvons par exemple l'afficher, l'insérer dans une autre chaîne, etc. Dans ce contexte, la valeur undef renvoie la chaîne vide : "".

Contexte de liste modifier

Comme son nom l'indique, il permet de manipuler des listes et également les tableaux. Dans ce contexte, une liste renvoie ses éléments. Si une liste est undef alors elle renvoie une liste d'un élément undef.

Exemples modifier

Un certain nombre d'opérateurs forcent le contexte.

contexte (scalaire) numérique modifier

my $a = "10.0" + 5; # L'opérateur + force le contexte numérique et l'expression renvoie la valeur 15
my $b = @tableau ; # $b est de type scalaire (sigil $) donc le tableau renvoie son nombre d'éléments

Une manière de forcer le contexte scalaire est d'utiliser la fonction scalar.

my @tab2 = scalar(@tab); # @tab2 contient comme premier élément le nombre d'éléments de @tab

contexte de liste modifier

my @tableau2 = @tableau; # @tableau2 est de type liste (sigil @) donc @tableau renvoie sa liste d'éléments

À noter qu'il est possible de forcer le contexte de liste avec un scalaire comme variable à gauche de l'affectation.

my $a = @tableau; # contexte numérique, renvoie le nombre d'éléments de @tableau
my ($b) = @tableau; # contexte de liste, $b contient donc le premier élément de @tableau.

Précision : my ($a, $b, $c) = (1, 2, 3) est une façon correcte de faire des déclarations multiples et simultanées de variables.

my ($a, $b, $c) = @tableau; # contexte de liste, $a, $b, $c contiennent donc respectivement les trois premiers éléments de @tableau.


Fonctions sur listes

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Rappels sur les listes modifier

Une liste est une suite de mots, de nombres… tout scalaire à vrai dire. Une liste stockée forme un tableau ou un tableau associatif (que nous verrons plus loin).

une liste modifier

Pour créer une liste on utilise les parenthèses () de cette manière :

( "5.0", "truc" , 7, $autre_valeur )

Nous avons là une suite de scalaires : "5.0", "truc", 7 et la valeur stockée dans la variable scalaire $autre_valeur.

créer un tableau modifier

Pour pouvoir la manipuler plus tard dans le programme, nous la stockons dans une variable. La variable est donc un tableau signalé par le sigil @.

Exemple avec parenthèses :

my @bon_a_manger = ( "poire", "chocolat", "sucre", "sirop", "bonbons", "fromage" );

Mais il y a d'autres opérateurs dédiés à la création de listes, comme qw qui crée une liste de mots (quoted words). Cet opérateur est préféré aux parenthèses dû à sa concision.

Exemple avec qw :

my @bon_a_manger = qw/poire chocolat sucre sirop bonbons fromage/;

La création de la liste est plus concise. Mais ceci va plus loin encore (voir la création de tableaux associatifs avec qw).

Créer un tableau associatif modifier

Un tableau associatif (ou table de hachage) est une structure permettant d'associer à un scalaire un autre scalaire. C'est une liste un peu plus complexe qu'un tableau et le sigil est différent (%).

La création de ce type de liste se fait également avec des parenthèses, mais on ajoute également (facultatif) un opérateur => pour voir facilement la clé et sa valeur :

my %bon_a_manger = ( "fruit" => "cerise", "légume" => "patate" );

À savoir : l'opérateur => force l'interprétation de la variable à sa gauche comme une chaîne de caractères, donc les guillemets sont inutiles. Même exemple, mais avec qw :

my %bon_a_manger = qw/fruit cerise légume patate/;

Là encore nous voyons la concision apportée par cet opérateur. %bon_a_manger a le sigil % donc Perl sait qu'il doit ranger les mots par paires de la manière clé-valeur ("fruit" => "cerise", "légume" => "patate").

Fonctions de manipulation de listes modifier

Il existe un nombre assez conséquent de fonctions de manipulation de listes (tableaux, tableaux associatifs). Nous allons aborder les plus courantes. Il n'est pas obligatoire de les connaître toutes par cœur.

.. : créer une suite d'éléments modifier

On pourrait vouloir par exemple créer des suites longues d'éléments qui s'enchaînent. Par exemple, avec l'opérateur .. écrire une suite de 1 à 100 n'est pas plus compliqué que :

( 1 .. 100 ) # toutes les valeurs entières de 1 à 100

Nous pouvons faire également la même chose avec des lettres :

( 'a' .. 'z' ) # renvoie toutes les lettres de l'alphabet

exemple : les lettres de 'a' à 'zz' modifier

Nous allons afficher à l'écran toutes les combinaisons des lettres de 'a' à 'zz' :

foreach my $var ( 'a' .. 'zz' )
{
	say $var; # affiche tour à tour chacune des valeurs de 'a' à 'zz'
}

join : concatène tous les éléments d'une liste modifier

La commande join permet de concaténer tous les éléments d'une liste avec un motif (une chaîne de caractères par exemple) entre chaque élément.

Exemple : afficher tous les éléments d'un tableau séparés par un double point.

my @fruits = qw/ poire cerise pomme fraise /;
say join(' : ', @fruits);

Affichera : « poire : cerise : pomme : fraise ».

map : transforme tous les éléments d'une liste modifier

Conseil : pour comprendre correctement cette fonction, voyez au moins le cours sur les fonctions et les procédures.

Cette fonction applique une transformation à tous les éléments d'un tableau ou d'une table de hachage. map prend en argument un bloc de code à exécuter et une liste (ou tableau). Il retourne une liste d'éléments modifiés.

Un exemple simple, on va doubler les valeurs d'un tableau :

my @simple = ( 1 .. 3 );
my @double = map { $_ * 2 } @simple; # on double toutes les valeurs
say foreach @double; # 246

Comme plus haut mais en une seule ligne :

say foreach map { $_ * 2 } ( 1 .. 3 ) ; # ce code est un peu plus dur à lire que les autres, n'hésitez pas à le relire plusieurs fois

Écrire du code aussi compact est très pratique à l'usage, mais pour un débutant il n'est pas nécessaire de savoir écrire de façon aussi concise.

grep : récupère une partie des éléments d'une liste modifier

Se manipule comme map, et permet de récupérer une liste d'éléments contenus dans une liste suivant certaines conditions. Exemple : les éléments numériques inférieurs à 10 :

my @tableau_1_a_100 = ( 1 .. 100 );
my @inferieurs_a_10 = grep { $_ < 10 } @tableau_1_a_100 ;
say foreach @inferieurs_a_10; # affiche chaque élément de @inferieurs_a_10 suivit d'un retour à la ligne

defined : savoir si un élément de la liste est défini modifier

exists : savoir si un élément d'une liste existe modifier

Cette fonction permet de savoir si un élément d'une liste existe. Attention : ceci ne permet pas de savoir si l'élément est défini.

delete : supprimer un élément d'une table de hachage modifier

keys : retourne toutes les clés d'une table de hachage modifier

Renvoie une liste des clés d'une table de hachage.

my %hash = qw/ fruit poire légume carotte/;
say join(' : ', keys (%hash));

Affiche : « légume : fruit ».

values : retourne toutes les valeurs d'une table de hachage modifier

Renvoie une liste des valeurs contenues dans une table de hachage.

my %hash = qw/ fruit poire légume carotte/;
say join(' : ', values(%hash));

each : retourne un couple clé-valeur d'une table de hachage modifier

Cette fonction est très utile pour boucler sur tous les éléments d'un tableau associatif.

my %hash = qw/ fruit poire légume carotte/;
say "Un couple 'clé - valeur' : ", join( " - " , each %hash);

Affichera : « Un couple 'clé - valeur' : légume - carotte » .

pop : retire le dernier élément d'une liste et le retourne modifier

Permet de supprimer le dernier élément d'une liste. Il retourne cet élément, donc on peut le récupérer.

my @fruits = qw/ poire cerise pomme fraise /;
say pop @fruits; # affichera "fraise"
# @fruits ne contient plus que "poire", "cerise" et "pomme"

push : ajoute à la fin de la liste un nouvel élément modifier

Cette fonction ajoute un élément à la fin d'une liste.

On reprend l'exemple plus haut en ajoutant push pour remettre « fraise » :

my @fruits = qw/ poire cerise pomme fraise /;
say pop @fruits; # affichera "fraise"
# @fruits ne contient plus que "poire", "cerise" et "pomme"
push @fruits, "fraise"; # @fruits contient à nouveau "fraise" en dernière position

shift : supprime le premier élément d'une liste et le retourne modifier

Il suffit de faire shift @tableau, exemple :

my @bon_a_manger = qw/fruit cerise légume patate /; # un simple tableau
my $aliment = shift @bon_a_manger;	# on supprime le premier élément du tableau et on le récupère (facultatif)
say $aliment; # affichera « fruit » qui était le premier élément de @bon_a_manger
say join ':', @bon_a_manger; # affichera « cerise:légume:patate »

unshift : ajoute un élément au début d'une liste modifier

Exemple simple d'utilisation de unshift :

my @bon_a_manger = qw/fruit cerise légume patate /; # un simple tableau
my $aliment = "fromage"; # un simple scalaire
unshift @bon_a_manger, $aliment; # on ajoute le scalaire "fromage" au début du tableau @bon_a_manger
say join ':', @bon_a_manger; # affichera « fromage:fruit:cerise:légume:patate »

reverse : inverse tous les éléments d'une liste (le dernier devient premier, etc.) modifier

On fait simplement reverse @tableau.

Le tri alphabétique inverse en devient on ne peut plus clair.

#!/usr/bin/perl -w
use strict;
my @tableau = qw(d a c e b);
my @tri = reverse sort @tableau; # e d c b a
print "@tri\n";#

splice : manipule des tranches de listes modifier

#!/usr/bin/perl
use strict;
use warnings;
# splice est aux listes d‘items ce que
# substr est aux chaînes de caractères

# extraction
my @tableau= qw(ba be bi bo bu fa fe fi fo fu);
print splice (@tableau,2,3)."\n"; # bu dernier éliminé après bi et bo
print "@tableau\n";# ba be fa fe fi fo fu

# extraction du 5e à l'antépénultième
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,4,-2);
print "@tableau\n";# ba be bi bo fo fu

# comptage depuis la fin
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,-5,2);
print "@tableau\n";# ba be bi bo bu fi fo fu

# jusqu‘à l'avant-dernier
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,-4,-1);
print "@tableau\n";# ba be bi bo bu fa fu

# remplacement de 4 items par XX
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,2,4,"XX");
print "@tableau\n";# ba be XX fe fi fo fu

# gommage = remplacement vide
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,3,5);
print "@tableau\n";# ba be bi fo fu

# incrustation = remplacement sur une longueur de zéro
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,4,0,"YY");
print "@tableau\n";# ba be bi bo YY bu fa fe fi fo fu

# préfixage = fonction unshift
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,0,0,"PREF_");
print "@tableau\n";# PREF_ ba be bi bo bu fa fe fi fo fu

# suffixage = fonction push
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
my $Nombre = @tableau;
splice(@tableau,$Nombre,0,"_SUFF");# ba be bi bo bu fa fe fi fo fu _SUFF
print "@tableau\n";

scalar : retourne le nombre d'éléments d'une liste modifier

Cette fonction n'a aucune utilité si on est en contexte scalaire, par exemple :

$nb_elements = @tableau;

Cependant, lorsque nous sommes en contexte de liste, il sera déjà plus utile :

my @tableau_1 = qw/voiture avion vélo/;		# un tableau quelconque
my @tableau_2 = qw/train skateboard moto/;	# un second tableau quelconque

# ici, nous souhaitons stocker le nombre d'éléments de chaque tableau
# et ne pas simplement créer un tableau contenant toutes les valeurs des deux tableaux
my @nombres_elements = (scalar(@tableau_1), scalar(@tableau_2));

Ici, le code que nous avons créé permet de créer un tableau @nombres_elements qui contient le nombre d'éléments de deux précédents tableaux. Sans scalar, nous aurions un tableau contenant l'ensemble des scalaires des deux premiers tableaux. Cela est dû à l'aplatissement des tableaux.

sort : ordonne une liste modifier

#!/usr/bin/perl
use strict;
use warnings;

my @tableau = qw(9 -.2 -4 34 -7 0 111);
# tri implicitement alphabétique
my @tri = sort @tableau;
print "@tri\n";# -.2 -4 -7 0 111 34 9

# tri explicitement alphabétique
@tri = sort ({$a cmp $b} @tableau);
print "@tri\n";# -.2 -4 -7 0 111 34 9

# tri inverse alphabétique
@tri = sort ({$b cmp $a} @tableau); # autre syntaxe : @tri = reverse sort @tableau;
print "@tri\n";# 9 34 111 0 -7 -4 -.2

# tri explicitement numérique
@tri = sort ({$a <=> $b} @tableau);
print "@tri\n";# -7 -4 -.2 0 9 34 111

# tri inverse numérique
@tri = sort ({$b <=> $a} @tableau);
print "@tri\n";# 111 34 9 0 -.2 -4 -7

# tris tarabiscotés sans intérêt autre que montrer les possibilités de "sort"

@tableau = qw(3 1 6 5 3 1 6 5);
# tri croissant sur une moitié, décroissant sur l‘autre
my $moitie = scalar @tableau / 2; # scalar est facultatif : my $... = environnement scalaire
@tri = ((sort ({$a <=> $b} splice (@tableau,0,$moitie))),(sort ({$b <=> $a} splice (@tableau,-$moitie,$moitie))));
print "@tri\n";# 1 3 5 6 6 5 3 1

@tableau = qw(9 -.2 -4 -14 -7 0 11);
# tri aux normes croissantes
@tri = sort ({abs $a <=> abs $b} @tableau);
print "@tri\n";# 0 -.2 -4 -7 9 11 -14

@tableau = qw(ab a abcd abc abcde);
# tri aux longueurs décroissantes
@tri = sort ({length $b <=> length $a} @tableau);
print "@tri\n";# abcde abcd abc ab a


Opérateurs

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Opérateurs numériques modifier

Perl reprend tous les opérateurs classiques (+, -, *, /, %, sin, cos) et les étend. Il y a des raccourcis utiles à connaître pour l'affectation, comme ++, --, +=, -=, *=, %= Il existe également l'opérateur exponentiel **.

exemples modifier

my $a = 1 ;
$a--;                   # $a vaut 0 ; est équivalent à "$a = $a - 1;"
$a = $a + 2;    # $a vaut 2 ; est équivalent à "$a += 2;"
$a *= 2;                # $a vaut 4 ; est équivalent à "$a = $a * 2;"
$a -= 10;               # $a vaut -6 ; est équivalent à "$a = $a - 10;"
$a++;                   # $a vaut -5 ; etc.

Il faut être attentif aux opérations avec ++ et -- . $b = $a++ affecte à $b la valeur de $a **avant** son incrémentation. $b = ++$a affecte à $b la valeur de $a **après** son incrémentation.

Opérateurs de chaînes modifier

Les opérateurs les plus basiques qui travaillent sur des chaînes sont :

  • . : concaténation
  • length : connaître la taille d'une chaîne
  • chop : retire le dernier caractère d'une chaîne
  • chomp : comme chop mais seulement si le dernier caractère est un retour à la ligne
  • split : permet de couper une chaîne suivant un motif
  • join : regroupe les éléments d'une liste, avec une chaîne entre tous les éléments
  • reverse : inverse les éléments d'une liste (le premier devient le dernier et inversement)
  • substr : prend une partie de la chaîne
  • index : cherche l'indice de la première occurrence d'une chaîne dans une autre
  • rindex : inverse de la fonction index, cherche la dernière occurrence

exemples modifier

my $str = "coucoux";
say length( $str ), " ", index( $str, "uc" ); # affiche "7 2"
chop $str;      # supprime la lettre 'x'
say $str;       # affichera "coucou"
my @tableau_de_caracteres = split("", $str); # contient la liste des lettres restantes
say join(" | ", @tableau_de_caracteres);         # affiche  c | o | u | c | o | u

explications modifier

say length( $str ), " ", index( $str, "uc" );

Ici, nous appellons la fonction say pour qu'elle affiche la taille de la chaîne de caractères $str (7), un espace (" ") et l'index de la première occurrence de "uc" (2). Nous verrons plus tard comment se passent les passages de paramètres et retours de fonctions.

my @tableau_de_caracteres = split("", $str);

La fonction split permet de séparer une chaîne de caractères suivant un motif, ici la chaîne vide : "". Ceci a pour conséquence de séparer toutes les lettres.

say join(" | ", @tableau_de_caracteres);

Nous affichons le retour de la fonction join qui renvoie tous les éléments de @tableau_de_caracteres séparés par la chaîne " | ". Elle affiche donc "c | o | u | c | o | u".


Tests

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Les tests modifier

Il existe plusieurs manières d'effectuer un test, qui est couramment appelé « évaluer une expression » en jargon informatique. Nous allons voir les méthodes les plus courantes.

Les mots clés modifier

  • if, elsif, else, unless

Le mot clé utilisé pour faire des tests est if (ou unless si on veut tester négativement). Si le test échoue, nous pouvons mettre la condition "sinon si" : elsif. Nous pouvons enchaîner autant de elsif que nous le souhaitons. Un bloc de code est exécuté si tous les autres tests précédents ont échoué via le mot clé else. Unless peut être vu comme l'inverse de if (si n'est pas).

Syntaxe modifier

Syntaxe classique if elsif else modifier

Nous allons voir comment effectuer des tests et exécuter différentes parties du code en fonction des valeurs de nos variables. Cette syntaxe est particulièrement connue car utilisée dans de nombreux langages.

if ( expression )
{
        instructions
}
elsif ( expression )
{
        instructions
}
else
{
        instructions
}

Attention : il ne faut pas mettre de point virgule (;) à la fin de toutes les lignes, relisez bien le code pour savoir où les placer ! Contrairement à certains langages, nous ne pouvons pas ommettre les accolades ({}) dans cette version du test.

exemple modifier
my $a = 5;
my $b = 8;
if ( $a > $b )
{
        say "$a est plus grand que $b";
}
elsif ( $a < $b )
{
        say "$a est plus petit que $b";
}
else
{
        say "$a et $b sont égaux";
}

condition après instruction conditionnée modifier

instruction if ( expression ) ;

Ce code est bien plus court, et avec cette syntaxe nous n'avons pas besoin de mettre les parenthèses.

exemple modifier
my $a = 6;
my $b = 5;
say $a if $a > $b;

Ce code affiche "6" car $a > $b. Cependant, cette façon d'écrire le test d'une série d'expressions ne permet pas l'utilisation de elsif, de else, et ne permet l'exécution conditionnelle que d'une seule instruction.

Cette méthode permet de lire l'instruction conditionnée comme si on lisait une phrase => "fais ceci SI cela".

Syntaxe condition ternaire modifier

expression ? instruction_si_vrai : instruction_si_faux ;
exemple modifier
my $a = 6;
my $b = 5;
$a > $b ? say "$a plus grand que $b" : say "$a plus petit que $b" ;

$a ( valeur = 6) est plus grand que $b (valeur = 5) donc on affiche "$a plus grand que $b".

Opérateurs de tests modifier

Il y a un certain nombre d'opérateurs qui permettent de faire des tests sur des nombres (scalaires numériques), des chaînes (toujours des scalaires) ou des listes.

Opérateurs de tests numériques modifier

Tout d'abord, les tests de comparaisons classiques comme dans les autres langages (et en mathématiques) :

  • < , > , <= , >= , == , !=

Ils nous permettent de faire des tests très simples "si $a plus grand que $b". Un peu moins répandu :

  • <=>
#!/usr/bin/perl -w
use strict;

# opérateur <=>, ses 3 réponses possibles

my ($a,$b)= (5,6);
print ($a<=>$b);# -1
print "\n";

print ($b<=>$a);# 1
print "\n";

($a,$b)= (5,5);
print ($a<=>$b);# 0
print "\n";

Opérateurs de tests sur chaînes modifier

Ces opérateurs travaillent sur des chaînes de caractères. Une chaîne "plus petite" qu'une autre est une chaîne qui apparaît avant dans l'ordre lexicographique.

  • lt (plus petit que) , gt (plus grand que),
  • le (plus petit ou égal) , ge (plus grand ou égal) ,
  • eq (égal) , ne (non égal).
exemple modifier
my $chaine1 = "coucou";
my $chaine2 = "zzz";
if( $chaine1 lt $chaine2 ) # rappel : lt = plus petit que dans ordre lexicographique
{
        say $chaine1;
}
elsif( $chaine2 lt $chaine1 ) # si $chaine2 arrive plus tôt dans l'ordre lexicographique que $chaine1
{
        say $chaine2;
} 
else
{
        say "Les chaînes sont égales !";
}
valeurs booléennes retournées: 1 ou vide modifier
#!/usr/bin/perl -w
use strict;

my ($a,$b)= (5,6);
print ($a lt $b);# 1
print "\n";

print">>>";
print ($a gt $b);# >>><<< chaine vide mais définie !
print "<<<\n";
print defined ($a gt $b);# 1

Opérateurs pour tester plusieurs expressions modifier

Commençons par les mots clés :

  • or, and,  : « ou » et « et »
  • ||, &&  : « ou » et « et »

Nous verrons plus tard la notion de précédence.

Ce qu'il faut savoir pour évaluer plusieurs expressions est que l'on peut combiner des expressions pour en former une seule grande. Comme nous l'avons vu, une expression est souvent un test entre parenthèses :

( $a >= $b )

Nous pouvons créer une expression plus grande, combinant celle-ci avec d'autres :

 (($a >= $b) || ($a == 5))

Ici, nous évaluons la première expression ($a >= $b) et avec le « ou » (les deux barres verticales ||) nous évaluons la seconde expression seulement si la première a échouée ($a est un nombre inférieur à $b). Si à la place du « ou » (||) nous avions un « et » (&&), il faudrait que les deux expressions qui l'entourent soient testées positivement pour que l'expression globale soit vraie.

exemple modifier
my $a = 5 ;
my $b = 10 ;
say "$a" if( ($a < $b && ($a * 2) > $b) || $a == 5);

On affiche $a si ($a est inférieur à $b et que son double ($a * 2) est supérieur à $b) ou si $a est égal à 5. $a ne correspond pas au premier test entre parenthèses ($a < $b && ($a * 2) > $b) car une des deux conditions nécessaires n'est pas remplie. Donc le premier test est négatif et on va exécuter la seconde série de tests après le « ou » (||), $a est égal à 5, donc la série globale est validée. On affiche 5 (la valeur de la variable $a).


Itérations

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Boucles et syntaxe modifier

Les boucles permettent simplement de ré-exécuter un bloc de code. Perl offre des outils très puissants pour parcourir aisément des listes (tableaux, tableaux associatifs).

Boucle while et until modifier

Boucle classique, déjà vue dans un bon nombre de langages.

Syntaxe modifier

while( expression ) { instructions }
until( expression ) { instructions }

La seule différence entre while et until est que while boucle tant que l'expression est vraie, until jusqu'à ce qu'elle le soit.

exemples modifier

# while
my @fruits = qw/ cerise pomme pastèque /;
while( @fruits ) # une fois la liste @fruits vide, l'expression sera évaluée fausse
{
        say pop @fruits; # rappel : pop supprime le dernier élément et le retourne
}

# until
@fruits = qw/ cerise pomme pastèque /;
until ( !(@fruits) ) # liste vide = faux, !faux = vrai, until s'arrête
{
        say pop @fruits; # pastèquepommecerise
}

Tant qu'il reste des éléments dans @fruits on boucle, et à chaque itération on pop (suppression du dernier élément d'une liste) un élément qu'on affiche.

Boucle for modifier

Permet de boucler comme dans le langage C.

Syntaxe modifier

for([expression] ; [expression] ; [expression]) { instructions }

La première expression est ce qui est effectué avant de commencer à boucler, la seconde est un test qui est effectué à chaque début de boucle, pour savoir si on continue de boucler, la dernière est une expression qui s'effectue à chaque fin d'itération.

Vous aurez remarqué que les 3 expressions sont écrites entre crochets [], c'est parce qu'elles sont toutes les 3 facultatives.

exemples modifier

my @fruits = qw/ cerise pomme pastèque /;
for(my $i = 0 ; $i < @fruits ; $i++) # $... = contexte scalaire donc "scalar @fruits" est facultatif 
{
        say $fruits[$i]; # $i ème élément de la liste @fruits
}
explications modifier
for(my $i = 0 ; $i < @fruits ; $i++)

Première expression : on crée la variable $i qu'on initialise à 0. Seconde expression : on teste si $i est inférieure à la taille de @fruits. Dans cette condition, on utilise l'opérateur numérique < qui force le contexte scalaire, donc @fruits renvoie son nombre d'éléments. Troisième expression, on incrémente $i (à chaque fin de boucle).

say $fruits[$i];

On affiche la ième valeur de la liste @fruits. Ceci se rapproche de la manière de boucler sur des listes et tableaux dans d'autres langages.

Boucle do while modifier

La différence entre une boucle while comme vu plus haut et une boucle do while est qu'on rentre déjà une première fois dans la boucle même si la condition du while n'est pas vraie.

Syntaxe modifier

do { instructions } while (expression);
do { instructions } until (expression);

exemples modifier

#!/usr/bin/perl -w
use strict;

my $valeur_max = 6;
my $indice = 0;
do
{  
        say "$indice "; # 0 1 2 3 4 5
} while ++$indice < $valeur_max ;

print "\n";

# $indice > 6
$indice = 9;
do
{ 
        say "$indice "; # 9 tout seul
} while ++$indice < $valeur_max ;

On effectue la boucle de toutes façons une fois. Si $indice est déjà égal ou supérieur à $valeur_max on l'affichera au moins une fois.

Boucle foreach modifier

Permet de parcourir toute une liste (tableau, tableau associatif).

Syntaxe modifier

foreach my $variable ( tableau ) { instructions }
instruction foreach ( tableau ) ;

exemples modifier

my @fruits = qw/ cerise pomme pastèque /;
foreach my $fruit (@fruits)
{
        say  "$fruit "; # cerise pomme pastèque 
}

Un exemple simple pour montrer la concision d'un code Perl. Nous verrons plus loin les mécanismes qui permettent ceci :

my @fruits = qw/ cerise pomme pastèque /;
say foreach "@fruits";

Boucle sur un tableau associatif modifier

Il y a plusieurs façons de faire.

Syntaxe modifier

foreach my $cle (keys %tab_asso) { instructions } # clé courante = $cle et valeur courante = $tab_asso{$cle}
while (my ($cle, $valeur) = each %tab_asso) { }

exemples modifier

En utilisant foreach et keys :

Contrairement à "for", l‘ordre de sortie est aléatoire, néanmoins tout y est !

my %tab_asso = qw/ a 1 b 2 c 3 d 4 e 5/;

foreach my $cle (keys %tab_asso)
{
        say $cle , $tab_asso{$cle}," "; # c3 d4 e5 a1 b2 ou bien d4 b2 e5 a1 c3 ou bien …
}

Avec while et each :

my %tab_asso = qw/ a 1 b 2 c 3 d 4 e 5/;

while (my ($cle, $valeur) = each %tab_asso)
{
        say $cle , $valeur," "; # e5 a1 d4 c3 b2 ou bien …
}


Fonctions et procédures

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Introduction modifier

Quelques définitions modifier

Déjà, il est bon de savoir ce qu'est une fonction. Une fonction permet de factoriser du code, si on a besoin d'exécuter une même portion de code à des endroits différents, ou pour simplifier la lecture d'un code, il est préférable de séparer certaines instructions et d'y faire appel le moment venu.

Petit instant vulgarisation : un exemple simple pour se représenter ce qu'est une fonction est de s'imaginer toutes les actions que nous avons besoin de faire pour aller faire les courses au marché. Vous dites « aller faire les courses » et pas « prendre mes clés, mon argent, sortir de chez moi, fermer la porte, prendre la voiture … ». Une fonction permet donc ceci: « s'abstraire » de toutes les actions entre le moment où vous partez et le moment où vous revenez. Ce qu'il faut pour que cette série d'action se déroule bien, ce serait avoir un peu d'argent ; prenez ceci comme exemple de paramètre. Pour aller faire les courses (la fonction), il faut un peu d'argent (paramètre de la fonction), et à la fin vous avez vos courses (retour de fonction).

Ce qu'est une fonction en Perl modifier

En Perl, il y a plusieurs manières d'appeler ou même de faire des fonctions, tout comme il y a plusieurs manières de tout faire. Il n'y a pas forcément une méthode meilleure que l'autre, si ce n'est au niveau de la visibilité du point de vue d'un œil non averti.

Nous commencerons à voir comment se fait l'appel d'une fonction (que nous avons vu sans en parler jusque-là), puis comment créer sa propre fonction et comment récupérer les paramètres.

À savoir : généralement en Perl nous parlons de « routine » pour dire une fonction que vous créez vous-même. Le mot « fonction » est généralement utilisé pour parler des fonctions intégrées directement dans le langage.

Les appels de fonction modifier

Nous avons déjà vu comment appeler une fonction, par exemple :

say "hello !";

Ici nous avons un appel à la fonction "say" et nous passons en paramètre "hello !". Plus classiquement dans les autres langages, des parenthèses sont utilisées pour distinguer la fonction de ses paramètres, ceci donnerait :

say( "hello !");

En Perl, il n'y a pas d'obligation. Pour passer plusieurs paramètres, Pour enchaîner plusieurs fonctions à la suite, il est parfois nécessaire de mettre des parenthèses pour lever l'ambigüité sur quels sont les paramètres utilisés pour quelle fonction.

say "début de ligne " , join ':', qw/mots du milieu/ , " fin de ligne."
# début de ligne mots:du:milieu: fin de ligne.

Si on cherche à écrire cette fonction de manière plus claire, ceci donne :

say("début de ligne ", join(':', qw/mots du milieu/, " fin de ligne."));

On remarque plus facilement la différence entre les paramètres de say et ceux de join. Aussi, si on avait envie que join ne prenne que ':' et qw/mots du milieu/ en paramètre, il aurait fallu écrire :

say "début de ligne ", join(':', qw/mots du milieu/), " fin de ligne.";

Assez souvent une fonction renvoie une valeur. Dans l'exemple précédent, la fonction join renvoie une chaîne de caractères (un scalaire) et on réutilise tout de suite cette valeur comme paramètre à l'appel de la fonction say. On aurait évidemment pû récupérer cette valeur :

my $chaine = join(':', qw/mots du milieu/);
say "début de ligne ", $chaine , " fin de ligne.";

Créer une fonction modifier

Syntaxe modifier

Cela se fait avec le mot clé sub (pour « subroutine » ) suivit du nom que vous souhaitez donner à la fonction, puis d'un bloc de code. La syntaxe la plus simple est :

sub nom_de_la_fonction 
{
        # instructions
}

Il n'y a pas de règle pour le placement des accolades, vous pouvez très bien mettre l'accolade ouvrante sur la même ligne que le nom de la fonction que vous créez si vous trouvez ça plus naturel.

Récupérer des paramètres envoyés à la fonction modifier

Maintenant on va vouloir passer des paramètres à notre fonction. Il faut savoir qu'en Perl, il n'y a pas besoin d'indiquer les paramètres d'une fonction.

Pour récupérer les paramètres d'une fonction, vous pouvez prendre les valeurs qui se trouvent dans la variable spéciale @_. Cette variable fait partie des variables qui changent au cours du temps, en fonction du moment où elles sont appelés. Dans ce contexte (rien à voir avec les contextes des variables), @_ vaut simplement la liste de paramètres que vous envoyez à votre fonction. Comme cette variable change au cours du temps, il est préférable d'en faire une copie dans un tableau en tout début de fonction, pour récupérer les paramètres et être sûr de pouvoir les réutiliser par la suite.

sub afficher {
        my @s = @_; # @_ contient actuellement tous les paramètres envoyés à la fonction
        say join ' : ' , @s;
}
afficher("test");

Donc tout ce que vous avez à faire pour récupérer des paramètres c'est de récupérer @_. À savoir qu'il y a quelques petites astuces à connaître pour récupérer des paramètres facilement. Prenons un exemple, une fonction qui fait une addition (et prend 2 paramètres) et affiche le résultat :

sub addition
{
        my ($a, $b) = @_;
        my $resultat = $a + $b;
        say $resultat;
}

Ici on peut voir qu'il y a des parenthèses autour des deux variables $a et $b ; ceci est pour forcer le contexte de liste. S'il y a plus de deux éléments dans @_ alors ils seront ignorés.

Retour de valeur modifier

Pour que la fonction retourne une valeur, il suffit d'utiliser le mot clé return. On peut renvoyer un scalaire, une liste (tableau, table de hachage…).

sub renvoyer_une_chaine 
{
        return "Cette fonction renvoie une chaîne de caractères";
}
say renvoyer_une_chaine ; # affichage de la valeur de retour de la fonction

Il est possible également de renvoyer plusieurs valeurs, elles seront renvoyés dans une liste et la récupération de ces valeurs peut se faire comme pour la récupération des paramètres dans une fonction.

sub addition
{
        my ($a, $b) = @_;
        my $resultat = $a + $b;
        return $a, $b, $resultat;
}

my ($a, $b, $resultat) = addition(5,6);
say "$a + $b = $resultat"; # 5 + 6 = 11

Pour renvoyer plusieurs résultats, il suffit de séparer les variables par des virgules, ce qu'on fait généralement pour séparer des paramètres à l'appel d'une fonction par exemple.


Les modules

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Ce que sont les modules modifier

Un module est une sorte de bibliothèque logicielle, qui possède des fonctionnalités réutilisables. Cela se présente sous la forme d'un fichier, où des tas de fonctionnalités sont écrites et qui touchent toutes à un type d'application, un protocole réseau, un usage, une thématique. Ce qui veut dire qu'un jour une personne a programmé un ensemble de fonctions qui vous permettent de faire quelque chose en particulier, comme par exemple créer une interface graphique ou jouer de la musique, et vous pouvez réutiliser le travail déjà réalisé, ce qui vous permet de gagner du temps.

Nous nous occuperons plus tard de la manière de créer un module, ici on va voir comment les utiliser.

Avant de commencer, sachez que les modules sont recherchés dans des répertoires. Cette liste est dans la variable globale @INC (INC pour include), pour l'afficher :

 perl -E "say for @INC"

L'ordre des répertoires est important, car si deux modules du même nom se retrouvent dans deux répertoires différents, seul le premier trouvé sera utilisé. Vous avez également la commande :

 perl -V 

Cette commande vous permettra d'obtenir beaucoup plus d'informations, n'hésitez pas à essayer cette commande.

Une fois que vous avez installé Perl, vous possédez une « distribution de Perl », ce qui veut dire que vous avez déjà un certain nombre de modules les plus utilisés.

Connaître les modules déjà installés sur le système modifier

Il y a deux options de perldoc à connaître pour savoir quels sont les modules installés. La première est pour savoir quels sont les modules installés par défaut avec votre « distribution » de Perl :

 perldoc perlmodlib

La seconde est pour connaître les modules installés en plus (ceux que vous avez installé ainsi que les modules qui ont été installés en tant que dépendance à ces modules).

 perldoc perllocal

Installer un module modifier

Pour installer des modules, je vous conseille d'installer le logiciel cpanminus qui permet d'installer très simplement n'importe quel module en tapant simplement :

 cpanm Le::Module

cpanminus gère également le téléchargement et l'installation des dépendances du module que vous cherchez à obtenir, il n'y a rien à faire.

Comment installer cpanminus modifier

Sous linux (TODO : à vérifier) (pensez à aller voir le site de votre distribution)
 aptitude install cpanminus    # Debian
 apt-get install cpanminus     # Ubuntu
 yum install cpanminus         # Fedora

Utiliser un module modifier

Pour utiliser simplement un module :

use nomdumodule;        # cas où le module est juste composé d'un fichier dans un des répertoires de @INC
use Le::Module;         # dans le cas où le module se trouve dans le répertoire « Le » lui-même dans un des répertoires de @INC

Prenons la ligne 2, ce que ce code fait est qu'il va chercher dans une liste de répertoires le dossier « Le » dans lequel il y aurait le fichier « Module.pm » (.pm pour Perl Module).

Une fois le module chargé, il ajoute des mots dans notre espace de nommage, c'est à dire qu'il nous permet d'appelé de nouvelles fonctions.

Une fois que vous avez chargé un module, vous ne pouvez plus le décharger.

un exemple concret modifier

On va chercher le répertoire courant via le module Cwd et la fonction getcwd.

use Cwd;

my $repertoire = getcwd();      # getcwd est une fonction dans le module Cwd
say "Nous sommes dans le répertoire $repertoire";

Si on n'avait pas inclut le module Cwd on n'aurait pas la fonction getcwd (pas dans notre espace de noms, fonction inconnue).

Voir la documentation d'un module modifier

Vous pouvez voir la documentation de n'importe quel module en tapant :

perldoc Le::Module

bash$perldoc Cwd

Réponse :

System::xxx::xxx::Perl::5.18::xxx::Cwd(3)

NAME
       Cwd - get pathname of current working directory

SYNOPSIS
           use Cwd;
           my $dir = getcwd;

           use Cwd 'abs_path';
           my $abs_path = abs_path($file);

DESCRIPTION
       This module provides functions for determining the pathname of the
       etc 

Où trouver des modules modifier

On ne va voir ici que des sites où tous les modules sont gratuits et que vous pouvez utiliser librement. Pour trouver des modules et donc des bouts de programme déjà fait, vous avez deux sites web qui sont les références en Perl à savoir :

  • search.cpan.org, CPAN (Comprehensive Perl Archive Network) : beaucoup de modules ;
  • Méta-CPAN : apporte des outils très intéressants pour choisir le bon module dans l'annuaire du CPAN ;

À savoir : chacun des modules est documenté avec POD (rappel : Plain Old Documentation) et ces sites vous permettent de voir leur documentation sous la forme HTML (directement sur le site donc) ainsi que des informations sur ces modules, comme par exemple une note qui leur est attribuée par les autres personnes utilisant le CPAN.

Le méta-CPAN permet quant à lui d'obtenir des informations comme la compatibilité du module

Comment choisir un module modifier

Pour bien choisir un module, nous prenons généralement un module avec un nom le plus générique possible, se rapprochant de ce que nous cherchons. Par exemple, si vous cherchez un module pour faire du réseau (échange de données entre différents ordinateurs tout simplement), vous allez chercher dans meta-cpan « network ».

Créer un module modifier

todo


Chaînes de caractères

Cette page est considérée comme une ébauche à compléter . Si vous possédez quelques connaissances sur le sujet, vous pouvez les partager en éditant dès à présent cette page (en cliquant sur le lien « modifier »).

Ressources suggérées : Aucune (vous pouvez indiquer les ressources que vous suggérez qui pourraient aider d'autres personnes à compléter cette page dans le paramètre « ressources » du modèle? engendrant ce cadre)

Le langage Perl permet de gérer les chaînes de caractères.

Comme il s'agit d'une langage ancien, il a d'abord été conçu pour gérer les anciens codages de textes (ASCII, iso-8859-x, etc.).

Le langage Perl s'adapte tout de même à son époque, et il est en particulier possible de traiter des textes Unicode. Si vous ne connaissez pas Unicode, vous pouvez le découvrir avec le livre À la découverte d'Unicode.

Des pages de manuels de Perl sont dédiées à l'Unicode, comme perlunicode ou perluniintro.

Fonctions de manipulation des chaînes modifier

substr
Extrait une sous-chaîne.
#!/usr/bin/perl
use strict;
use warnings;

my $chaine="babebibobu";
# extraction
print substr($chaine,4,2)."\n"; # bi

# extraction du 5e à l'antépénultième
$chaine="babebibobu";
print substr($chaine,4,-2)."\n"; # bibo

# comptage depuis la fin
$chaine="babebibobu";
print substr($chaine,-7,2)."\n"; # eb
#
# jusqu‘à l'avant-dernier
$chaine="babebibobu";
print substr($chaine,-7,-1)."\n"; # ebibob

# remplacement de 4 caractères par XX
$chaine="babebibobu";
substr($chaine,2,4,"XX");
print $chaine."\n"; # baXXbobu

# gommage = remplacement vide
$chaine="babebibobu";
substr($chaine,2,2,"");
print $chaine."\n"; # babibobu

# incrustation = remplacement sur une longueur de zéro
$chaine="babebibobu";
substr($chaine,4,0,"YY");
print $chaine."\n"; # babeYYbibobu

# préfixage
$chaine="babebibobu";
substr($chaine,0,0,"PREF_");
print $chaine."\n"; # PREF_babebibobu

# suffixage
$chaine="babebibobu";
substr($chaine,length $chaine,0,"_SUFF");
print $chaine."\n"; # babebibobu_SUFF

###########################
# autre syntaxe

# remplacement
$chaine="babebibobu";
substr($chaine,2,3)="XX";
print $chaine."\n"; # baXXibobu

# incrustation
$chaine="babebibobu";
substr($chaine,6,0)="YY";
print $chaine."\n"; # babebiYYbobu

# gommage
$chaine="babebibobu";
substr($chaine,2,6)="";
print $chaine."\n"; # babu

# préfixage
$chaine="babebibobu";
substr($chaine,0,0)="PREF_";
print $chaine."\n"; # PREF_babebibobu

# suffixage
$chaine="babebibobu";
substr($chaine,length $chaine,0)="_SUFF";
print $chaine."\n"; # babebibobu_SUFF


length
Calcule la longueur d'une chaîne.
#!/usr/bin/perl -w
# -w = "use warnings;"
use strict;

my $chaine="babebibobu";

print length $chaine; # 10
print "\n";

# lettres accentuées du français = 2 octets
my $chaine2="àâéèêëîïôùûçœæ";
print length $chaine2; # 28
print "\n";

# caractères spéciaux
print length "\t"; # 1 = UNE tabulation
print "\n";
print length "\\\n"; # 2 = une \ littéralement + un retour de chariot
print "\n";

# accepte toute chaîne quel que soit l‘emberlificotage de fonctions qui la crèe.
print length "devant".substr($chaine,-7,-1)x 3 ."derrière\n".sprintf ("%.5f",6/7)  ; # 41 dont devant = 6 ;  eBIboB x 3 = 18 ; derrière\n = 10 (è = 2) ; 0.85714 = 7 caractères
print "\n";
lc
Transforme une chaîne en minuscules.
#!/usr/bin/perl -w
# -w = "use warnings;"
use strict;

my $chaine="BaBeBiBOBU";
print lc "$chaine.\n"; # babebibobu

my $chaine2="fichier.TXT";
print  ucfirst substr( $chaine2,0,-4). lc substr( $chaine2,-4,4)."\n" ;# Fichier.txt
uc
Transforme une chaîne en majuscules.
#!/usr/bin/perl -w
# -w = "use warnings;"
use strict;
my $chaine="BaBeBiBOBU";
print uc $chaine."\n"; # BABEBIBOBU
lcfirst
Transforme le premier caractère d'une chaîne en minuscule.
#!/usr/bin/perl -w
# -w = "use warnings;"
use strict;

my $chaine2="Cornélien";
print lcfirst $chaine2."\n"; # cornélien
ucfirst
Transforme le premier caractère d'une chaîne en majuscule.
#!/usr/bin/perl -w
# -w = "use warnings;"
use strict;

my $chaine="corneille";
print ucfirst $chaine."\n"; # Corneille

my $chaine2="corneille, (auteur du cid.)";
print ucfirst substr( $chaine2,0,-5). ucfirst substr( $chaine2,-5,5)."\n" ; # Corneille, (auteur du Cid.)
chop
Supprime le dernier caractère d'une chaîne.

Il est utilisé surtout pour effacer les \n ("entrées" ou Carriage Return).

#!/usr/bin/perl -w
use strict;

# chop efface le dernier caractère de chaque item d'un liste
my @tableau =  ( "a\n" , "b\n", "c\n" );
print @tableau; # a b c sur 3 lignes distinctes

chop @tableau;
print @tableau; # abc accolés : les \n ont disparu

print "\n";

# chop renvoie son dernier effacement
my @tableau2 =  ( "vaches" , "veaux" );

print chop @tableau2;# le x de "veaux"
print "\n";

print @tableau2;# vacheveau
print "\n";
chomp
Permet de supprimer plusieurs caractères à la fin d'un chaîne.
#!/usr/bin/perl -w
use strict;

# création d‘un fichier cobaye de 3 lignes
# Descripteur de fichier = File Handle
open ( Descr0,'>','./cobaye') or die ("écriture impossible $!");
print Descr0 "premier\ndeuxieme\ntroisieme\n";
close(Descr0);

# lecture sans chomp -> affichage des 3 lignes
open (Descr1,'<','./cobaye') or die ("ouverture impossible $!");
while(defined (my $ligne = <Descr1> ) ){
    print $ligne;
}

# chomp efface le \n de chaque ligne lue dans cobaye -> affichage sur une seule ligne
open (Descr2,'<','./cobaye') or die ("ouverture impossible $!");
while(defined ( my $ligne = <Descr2> ) ){
    chomp $ligne;
    print $ligne;
}
close(Descr2);
close(Descr1);
print "\n";
reverse
Inverse l'ordre des caractères d'une chaîne.
#!/usr/bin/perl -w
use strict;

# renversement d‘une liste
my @tableau = qw(premier deuxieme troisieme quatrieme);
print reverse @tableau; # quatriemetroisiemedeuxiemepremier

print "\n";
# renversement d‘une chaîne (le 3e item)
my $envers= reverse $tableau[2];
print $envers;# emeisiort


Expressions régulières

Introduction modifier

Les expressions régulières sont des outils de l'informatique théorique permettant de décrire les langages de manière formelle. Elles sont implémentées dans beaucoup de langages de programmation dont Perl qui les utilisent avec une syntaxe étendue (fonction, code dans l'expression régulière, ...).

Ce chapitre peut vous être utile peu importe quel langage vous avez l'habitude de manipuler ou que vous utiliserez à l'avenir. N'hésitez pas à lire ce chapitre en plusieurs fois pour apprécier toutes les subtilités et pour comprendre à quel point ceci fait partie intégrante du langage Perl et comment bien se servir de ces outils.

Définition modifier

Une expression régulière est une manière de manipuler du texte de façon concise et claire à l'aide de motifs. Les expressions régulières (ou « rationnelles », aussi appelées « regex » pour « regular expression ») sont issues des théories mathématiques sur les langages formels.

Format modifier

Tout d'abord, nous utilisons le symbole =~ pour utiliser des expressions régulières, ensuite nous avons toute une panoplie de fonctionnalités à appliquer sur un texte (recherche, remplacement…), avec des options disponibles. Pour cela, voici la syntaxe :

$texte =~ fonction_voulue/première zone de texte[/seconde zone de texte si la fonction voulue le requiert]/[options];

Pour rappel, ce qui est entre crochets [] n'est pas toujours obligatoire. Le remplacement de texte par exemple nécessitera de rechercher du texte (première zone de texte) puis de le remplacer par un autre texte (seconde zone de texte). Pour la recherche de texte, pas besoin d'indiquer la seconde zone.

À savoir : cet exemple utilise des slashs (/) cependant nous pouvons utiliser d'autres caractères, comme l'underscore, un point d'exclamation, ou encore des accolades par exemple. Ceci est pratique lorsque nous avons à chercher un motif contenant des slashs (pas besoin de le banaliser, c'est à dire rajouter un antislash « \ » devant le caractère).

Exemple modifier

Un exemple simple d'utilisation serait de chercher un mot dans un texte, fonctionnalité m (Match en anglais) :

my $texte = "J'aime le fromage";
# la fonctionnalité "m" correspond à la recherche de motif
if( $texte =~ m/fromage/ ) # on n'utilise pas d'options
{
	say "On a trouvé « fromage » dans le texte";
}
else
{
	say "On n'a pas trouvé de fromage :(";
}

Comme on peut s'y attendre, ce code va afficher « On a trouvé « fromage » dans le texte » puisque nous recherchons le mot « fromage » dans $texte. En fait, la fonction cherche à savoir si le texte correspond (match en anglais) au motif spécifié. Celui-ci ne contenant pas d'ancre de début ou fin de texte, peut correspondre avec une partie se trouvant au milieu du texte.

Fonctionnalités modifier

Les expressions rationnelles peuvent être analysées et testées via un débogueur en ligne comme https://regex101.com/.

Expressions rationnelles courantes
Caractère Type Explication
. Point N'importe quel caractère
[...] crochets classe de caractères : tous les caractères énumérés dans la classe, avec possibilité de plages dont les bornes sont séparées par "-". Ex : [0-9a-z] pour tout l'alphanumérique en minuscule, ou [0-Z] pour tous les caractères de la table Unicode entre "0" et "Z", c'est-à-dire l'alphanumérique majuscule plus ":;<=>?@"[1].
[^...] crochets et circonflexe classe complémentée : tous les caractères sauf ceux énumérés.
[...[...]] union Union des deux ensembles
[...&&[...]] intersection Intersection des deux ensembles
^ circonflexe Marque le début de la chaîne ou de la ligne.
$ dollar Marque la fin de la chaîne ou de la ligne.
| barre verticale Alternative - ou reconnaît l'un ou l'autre
(...) parenthèses groupe de capture : utilisé pour limiter la portée d'un masque ou de l'alternative, grouper un motif répété ou capturer une séquence
\n référence Même séquence que celle capturée précédemment par le nème groupe de capture
\g{n} référence Même séquence que celle capturée précédemment par le nème groupe de capture
(?P<nom>pattern) Sous-motif nommé Nomme le résultat d'un groupe de capture par un nom.
\g{nom} référence Même séquence que celle capturée précédemment par le groupe de capture nommé nom.
\k<nom> référence Même séquence que celle capturée précédemment par le groupe de capture nommé nom.

Par défaut, les caractères et groupes ne sont pas répétés. Les quantificateurs permettent de spécifier le nombre de répétitions et sont spécifiés immédiatement après le caractère ou groupe concerné.

Quantificateurs
Caractère Type Explication
* astérisque 0, 1 ou plusieurs occurrences
+ plus 1 ou plusieurs occurrences
? interrogation 0 ou 1 occurrence
{...} accolades nombre de répétitions : spécifie le nombre de répétitions du motif précédent (minimum et maximum). Avec la présence de la virgule, quand le minimum est absent la valeur par défaut est zéro, quand le maximum est absent la valeur pas défaut est l'infini. Sans virgule (un seul nombre) il s'agit du nombre exact (minimum et maximum ont la même valeur). Exemples :
  • a{2} deux occurrences de "a",
  • a{1,10} (sans espace) entre une et dix,
  • a{,10} jusqu'à 10 fois (de 0 à 10),
  • a{3,} au moins 3 fois (de 3 à l'infini).

Par défaut les quantificateurs ne recherchent pas forcément la plus longue séquence de répétition possible. Il est possible de les suffixer avec un caractère pour modifier leur comportement.

Modificateurs de quantificateurs
Caractère Type Explication
? réticent Le quantificateur qui précède recherchera la plus petite séquence possible.
+ possessif Le quantificateur qui précède recherchera la plus grande séquence possible.

Remarques :

  • Les caractères de début et fin de chaîne (^ et $) ne fonctionnent pas dans [] où ils ont un autre rôle.
  • Les opérateurs * et + sont toujours avides, pour qu'ils laissent la priorité il faut leur apposer un ? à leur suite[2].
Classes de caractères POSIX[3]
Classe Signification
[[:alpha:]] n'importe quelle lettre
[[:digit:]] n'importe quel chiffre
[[:xdigit:]] caractères hexadécimaux
[[:alnum:]] n'importe quelle lettre ou chiffre
[[:space:]] n'importe quel espace blanc
[[:punct:]] n'importe quel signe de ponctuation
[[:lower:]] n'importe quelle lettre en minuscule
[[:upper:]] n'importe quelle lettre capitale
[[:blank:]] espace ou tabulation
[[:graph:]] caractères affichables et imprimables
[[:cntrl:]] caractères d'échappement
[[:print:]] caractères imprimables exceptés ceux de contrôle
Expressions rationnelles Unicode[4]
Expression Signification
\\ Antislash
\C Caractère spécial C non interprété : [ ] { } ( ) ? * . : \ & - ^ $
\Q...\E Séquence littérale non interprétée
\0xxx Caractère Unicode (1 à 3 chiffres octaux)
\a Alarme (ASCII 07)
\A Début de chaîne
\b Caractère de début ou fin de mot
\B Caractère qui n'est pas début ou fin de mot
\cX Caractère de contrôle ASCII (X étant une lettre)
\d Chiffre
\D Non chiffre
\e Escape (ASCII 1B)
\f Form-feed (ASCII 0C)
\G Fin de la correspondance précédente
\h Espace blanc horizontal [ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]
\H Non espace blanc horizontal [^\h]
\n Fin de ligne
\pL, \p{L}, \p{Letter} Lettre (dans tout langage)
\r Retour charriot
\R Retour à la ligne, équivaut à \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
\s Caractères espace [ \t\n\x0B\f\r]
\S Non caractères espace [^\s]
\t Tabulation
\uxxxx Caractère Unicode (4 chiffres hexadécimaux)
\v Espace blanc vertical [\n\x0B\f\r\x85\u2028\u2029]
\V Non espace blanc vertical [^\v]
\w Caractère alphanumérique : lettre, chiffre ou underscore
\W Caractère qui n'est pas lettre, chiffre ou underscore
\xxx Caractère Unicode (2 chiffres hexadécimaux)
\x{xx...x} Caractère Unicode (chiffres hexadécimaux)
\X Caractère Unicode du groupe de graphèmes étendu
\z Fin de chaîne

Constructeurs spéciaux : Ces fonctions précèdent l'expression à laquelle elles s'appliquent, et le tout doit être placé entre parenthèses.

  • ?: : groupe non capturant. Ignorer le groupe de capture lors de la numérotation des backreferences. Exemple : ((?:sous-chaine_non_renvoyée|autre).*).
    La présence d'un groupe capturant peut engendrer une allocation mémoire supplémentaire. Si une expression régulière particulièrement complexe provoque une erreur de mémoire, essayez de remplacer les groupes capturant non référencés et inutilisés par des groupes non-capturant en ajoutant ?: juste après la parenthèse ouvrante, et en décalant les numéros des groupes référencés.
  • ?> : groupe non capturant indépendant.
  • ?<= : positive lookbehind, vérifier (sans consommer) que ce qui précède correspond au motif spécifié. Exemple :
    Chercher une lettre u précédée d'une lettre q : (?<=q)u
  • ?<! : negative lookbehind, vérifier (sans consommer) que ce qui précède ne correspond pas au motif spécifié.
  • ?= : positive lookahead, vérifier (sans consommer) que ce qui suit correspond au motif spécifié.
  • ?! : negative lookahead, vérifier (sans consommer) que ce qui suit ne correspond pas au motif spécifié. Exemples :
    Chercher une lettre q non suivie d'une lettre u : q(?!u)
    ((?!sous-chaine_exclue).)
    <(?!body).*> : pour avoir toutes les balises HTML sauf "body".
    début((?!mot_exclu).)*fin[5] : pour rechercher tout ce qui ne contient pas un mot entre deux autres.
    (?!000|666) : pour exclure 000 et 666[6].

Options :

Les options d'interprétation sont en général spécifiées à part. Mais certaines API ne permettent pas de les spécifier. Il est possible d'insérer ces options dans l'expression régulière[7].

(?optionsactivées-optionsdésactivées)

Exemples :

  • Chercher un mot composé de voyelles sans tenir compte de la casse :
    (?i)[AEIOUY]+
  • Chercher un mot composé de voyelles en majuscules :
    (?-i)[AEIOUY]+

Les options s'appliquent à toute l'expression quel que soit leur position dans l'expression.


Nous allons faire un tour des fonctionnalités (que j'appellerai également modes) les plus utilisés.

recherche : m modifier

Pour effectuer des recherches dans une chaîne de caractère, nous utilisons la fonctionnalité m. C'est le mode par défaut, nous n'avons pas besoin de l'écrire.

#!/usr/bin/perl -w
use strict;

# ^ début de ligne 
@tableau = ("affiche", "âme", "à toi", " affiche");
print 'Test sur la regex : if ( $texte =~ m/^a/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/^a/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "(espace en-tête)";
print "\n" x 2;

# $ fin de ligne 
@tableau = ("affiche", "affiche.", "affiches");
print 'Test sur la regex : if ( $texte =~ m/che.$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/che.$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n" x 2;

# \. point échappé
@tableau = ("affiche", "affiche.", "affiches");
print 'Test sur la regex : if ( $texte =~ m/che\.$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/che\.$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print '(\. point échappé = vrai point, pas n‘importe quel caractère)';
print "\n" x 2;

# {…}
@tableau = qw(tttrès hutte haute hausse tousse);
print 'Test sur la regex : if ( $texte =~ m/[t]{1,2}/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/t{2,3}/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

remplacement : s modifier

Le mode s permet d'effectuer un remplacement (aussi appelé substitution) dans une chaîne. Ici, nous avons besoin d'utiliser les deux zones de textes, de cette manière : s/texte à changer/nouveau texte/ .

exemple de substitution modifier

my $texte = "J'aime le fromage.";
$texte =~ s/le fromage/les légumes/; # les légumes c'est plus sain que le fromage !
say $texte; # affiche « J'aime les légumes. »

stocker une expression régulière : qr modifier

my $regex_mail = qr{[\w-+.]+@[\w-]+(?:\.[\w-]+)+};
unless ("nom@example.com" =~ /$regex_mail/) {
	say "Ce n'est pas une adresse mail";
}

constructeurs spéciaux : modifier

?= préviseur positif (positive lookahead) modifier

#!/usr/bin/perl -w
use strict;
my $texte = "anticonstitutionnellement";

# On cherche un "ti" qui précède ("il prévoit") "on" (suite affichée pour la clarté)
$texte =~ /(ti(?=on).+)/;# 
print $1."\n"; # tionnellement

# un "ti" qui précède "tu"
$texte =~ /(ti(?=tu).+)/;# 
print $1."\n"; # titutionnellement

?! préviseur négatif (negative lookahead) modifier

#!/usr/bin/perl -w
use strict;
my $texte = "anticonstitutionnellement";

# On cherche un "ti" qui NE précède PAS "on" (suite affichée pour la clarté)
$texte =~ /(ti(?!on).+)/;# 
print $1."\n"; # ticonstitutionnellement

# un "ti" qui NE précède PAS "cons"
$texte =~ /(ti(?!cons).+)/;# 
print $1."\n"; # titutionnellement

?<= rétroviseur positif (positive lookbehind) modifier

#!/usr/bin/perl -w
use strict;
$texte = "anticonstitutionnellement";

# On cherche un "ti" qui suit "tu" (début affiché pour la clarté)
$texte =~ /(.+(?<=tu)ti)/;#
print $1."\n"; # anticonstituti

# un "ti" qui suit "an"
$texte =~ /(.+(?<=an)ti)/;#
print $1."\n"; # anti

?<! rétroviseur négatif (negative lookbehind) modifier

#!/usr/bin/perl -w
use strict;
$texte = "anticonstitutionnellement";

# On cherche un "ti" qui NE suit PAS "tu" (début affiché pour la clarté)
$texte =~ /(.+(?<!tu)ti)/;#
print $1."\n"; # anticonsti

# un "ti" qui NE suit PAS "an"
$texte =~ /(.+(?<!an)ti)/;#
print $1."\n"; # anticonstituti

?> constructeur tête de mule ! modifier

Attrape la chaîne correspondante maximale où il est ancré, et refuse de faire un pas en arrière

( pas de backtracking pour trouver toutes les sous-chaînes ).

#!/usr/bin/perl -w
use strict;

my $count=0;
my $texte="a"x 33 ."b";
# on cherche les séries a…ab & les sous-séries a…a

# sans ?>
$texte =~ /(a+b?)(?{print "$&\n"; $count++})(*FAIL)/;
print "Count=$count\n"; # 594

# avec ?>
$count=0;
$texte =~ /(?>(a+b?))(?{print "$&\n"; $count++})(*FAIL)/;
print "Count=$count\n"; # 33

Sert à l'optimisation :

Pour 2 000 "a", on attend 2 003 000 recherches (sans ?>) contre 2 000 seulement (avec ?>).

Correspondances modifier

Lors d'une recherche de motif, nous pouvons utiliser des caractères spéciaux (parfois appelés « méta-caractères ») pour rechercher un type de caractère (et non un caractère explicitement).

caractères et expressions de correspondance modifier

caractère quelconque : . modifier

Le point « . » correspond à un caractère quelconque. Lors d'une recherche, nous pouvons l'utiliser pour indiquer n'importe quel caractère, excepté le retour à la ligne (\n).

exemple utilisation du point modifier
#!/usr/bin/perl -w
use strict;

# le point .
my @tableau = qw(matin mâtin méthode admit);
print 'Test sur la regex : if ( $texte =~ m/m.t/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/m.t/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "(lettres accentuées = 2 octets)";
print "\n" x 2;

# double point ..
@tableau = qw(matin mâtin méthode admit);
print 'Test sur la regex : if ( $texte =~ m/m..t/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/m..t/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère alphabétique : [[:alpha:]] modifier

Pour rechercher un caractère alphabétique on utilise: [[:alpha:]] ou éventuellement [a-zA-Z].

#!/usr/bin/perl -w
use strict;

# [[:alpha:]]
my @tableau = qw(satin 264 mâtin àâéèêëîôùûæœç àâéèêëîôùûæœça);
print 'regex : if ( $texte =~ m/[[:alpha:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:alpha:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print '(voyelles accentuées non ASCII)';
print "\n";

caractère numérique : \d et [[:digit:]] modifier

Nous avons deux possibilités pour rechercher un caractère numérique : [[:digit:]] et \d. Pour chercher un caractère qui n'est pas un chiffre : \D.

#!/usr/bin/perl -w
use strict;

# [[:digit:]]
my @tableau = qw(satin 264 37.5lematin àâ68éèêëîôùûæœç);
print 'regex : if ( $texte =~ m/[[:digit:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:digit:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère hexadécimal : [[:xdigit:]] modifier

Cela correspond à tout caractère hexadécimal, c'est à dire tous les caractères numériques (de 0 à 9) et les lettres de A à F.

#!/usr/bin/perl -w
use strict;

# [[:xdigit:]]
my @tableau = qw(sAtin DEBAClE 0123456789ABCDEF abcdef ghijkl);
print 'regex : if ( $texte =~ m/[[:xdigit:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:xdigit:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère alphanumérique : [[:alnum:]] et \w modifier

Les caractères alphanumériques correspondent à l'ensemble des caractères numériques (0,1,2…) et aux lettres. La classe \w reconnaît, en plus de [[:alnum:]], le caractère «_». Pour chercher un caractère qui n'est pas un nombre ou une lettre ou «_» : \W.

#!/usr/bin/perl -w
use strict;

# non [[:alnum:]] = \W
my @tableau = qw(&§@$£()[]{}#°%_ sAtin 0123456789ABCDEF §ghijkl);
print 'regex : if ( $texte =~ m/\W/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/\W/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère d'espacement simple : [[:blank:]] modifier

Un espacement correspond à un espace, une tabulation.

#!/usr/bin/perl -w
use strict;

# [[:blank:]]
my @tableau = ( "ça va?", "tab  ulation","tabulation"," vu!");
print 'regex : if ( $texte =~ m/[[:blank:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:blank:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère d'espacement quelconque : \s et [[:space:]] modifier

On cherche ici un espacement tel qu'une tabulation, un espace, un saut de ligne ou de page. Pour chercher un caractère qui n'est pas un espacement : \S.

#!/usr/bin/perl -w
use strict;

# \S  = non [[:blank:]]
my @tableau = ( "   ", " ","t   "," v");
print 'regex : if ( $texte =~ m/\S/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/\S/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

lettre en minuscule : [[:lower:]] modifier

#!/usr/bin/perl -w
use strict;

# [[:lower:]]
my @tableau = qw( ABCDE ABCdE);
print 'regex : if ( $texte =~ m/[[:lower:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:lower:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

lettre en majuscule : [[:upper:]] modifier

#!/usr/bin/perl -w
use strict;

# [[:upper:]]
my @tableau = qw( abcde abcDe);
print 'regex : if ( $texte =~ m/[[:upper:]]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/[[:upper:]]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

caractère de ponctuation : [[:punct:]] modifier

correspondances partielles : [] modifier

Nous cherchons une correspondance avec uniquement une partie des caractères, nous utilisons alors []. Nous pouvons choisir d'énumérer explicitement tous les caractères dont nous souhaitons vérifier la correspondance en les écrivant entre ces crochets. Un moyen plus répandu (lorsque cela est possible) est d'utiliser une suite de caractères, par exemple de « a » à « z » de cette manière : [a-z]. Pour correspondre avec l'inverse de ce qu'on note entre crochets, il suffit de mettre en première lettre « ^ ». Ainsi, la recherche inverse de l'exemple précédent devient : [^a-z].

exemple de correspondance partielle modifier

Cherchons à faire correspondre uniquement les caractères de « a » à « e » en minuscule, de « G » à « L » en majuscule et les chiffres de « 0 » à « 5 » et les chiffres 7 et 9.

$texte =~ /[a-eG-K0-579]/;

crochets []

#!/usr/bin/perl -w
use strict;
# crochets []
@tableau = qw(affiche affole affuble affriole effectué effacer);
print 'Test sur la regex : if ( $texte =~ m/ff[a-df-np-s]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/ff[a-df-np-s]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

crochets [^…]

#!/usr/bin/perl -w
use strict;

# crochets [^…] 
@tableau = qw(affiche affole affuble affriole effectué effacer);
print 'Test sur la regex : if ( $texte =~ m/ff[^ieo]/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/ff[^ieo]/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

Options modifier

ignorer la casse modifier

La « casse » désigne en informatique la différence entre minuscule et majuscule. Si on choisi d'ignorer la casse, alors nous recherchons un motif sans distinction avec ou sans majuscules. Pour cela nous avons l'option i.

recherche en mode multi-ligne modifier

Nous recherchons un motif en traitant la chaîne en tant que constituée de plusieurs lignes. Concrètement, nous voulons que ^ et $ ne correspondent pas seulement au début et fin de la chaîne, mais aussi au début et fin de chaque ligne. Pour cela, nous avons l'option m.

exemple de recherche en mode multi-ligne modifier

my $texte = "Ce texte
est sur
plusieurs lignes";

# utilisation de l'option m dans une recherche (fonctionnalité de recherche m)
if( $texte =~ m/sur$/m ) 
{
	say "On a trouvé « sur » en fin de ligne";
}
else
{
	say "On n'a pas trouvé « sur » en fin de ligne";
}

faire correspondre . à un saut de ligne modifier

Lorsque nous faisons des recherches sur plusieurs lignes, on souhaiterait pouvoir considérer le saut de ligne comme un caractère quelconque (comme tous les autres). Nous pouvons faire cela avec l'option s.

exemple utilisation de l'option s modifier

Nous reprenons l'exemple précédent avec la recherche sur plusieurs lignes, désormais nous n'avons pas à écrire explicitement le saut de ligne, nous pouvons utiliser le métacaractère ..

my $texte = "Ce texte
est sur
plusieurs lignes";

if( $texte =~ m/sur.plusieurs/s ) 
{
	say "On a trouvé « sur plusieurs » dans le texte";
}
else
{
	say "On n'a pas trouvé « sur plusieurs »";
}

permettre d'écrire l'expression régulière avec des commentaires modifier

L'option « x » permet d'écrire une expression régulière sans tenir compte des caractères d'espacement. Ainsi, on peut espacer ses expressions avec des retours à la ligne si on veut, sans que cela n'influe sur votre expression. Si vous souhaitez rechercher une chaîne de caractères avec des espaces à certains endroits, il faudra l'indiquer explicitement dans votre expression avec la recherche d'un caractère d'espacement (voir plus haut).

appliquer un changement plusieurs fois dans la chaîne modifier

Lors de la substitution de texte, nous souhaiterions par exemple changer tous les caractères « a » par « b ». Par défaut, seule la première occurrence de « a » serait modifiée. Pour changer ce comportement et changer tous les « a », nous utilisons l'option g.

#!/usr/bin/perl -w
use strict;
# remplacement simple
my $texte = "affuble mutin hure mure fumé luit";
    print $texte."\n";
    $texte =~ s/u/a/;
    print $texte;
print "\n" x 2;

# remplacement multiple
$texte = "affuble mutin hure mure fumé luit";
    print $texte."\n";
    $texte =~ s/u/a/g ;
    print $texte;
print "\n";

cumuler les options modifier

Nous pouvons additionner les options en les écrivant à la suite (/ig par exemple). Nous avons déjà vu un exemple plus haut en cumulant les options m (recherche de motif sur plusieurs lignes) et s (retour chariot inclut dans les caractères auxquels le point correspond). Autre exemple, nous pouvons effectuer une substitution plusieurs fois par ligne en ignorant la casse du motif à remplacer.

Ancres modifier

Les ancres correspondent au placement du texte à rechercher.

rechercher en début de chaîne : ^ et \A modifier

On utilise pour cela le caractère ^ ou \A qui correspond au début de la chaîne. Avec l'option /m le caractère ^ correspond également à tout début de ligne (voir plus haut).

exemple de recherche en début de chaîne modifier

my $texte = "Hello world!";
$texte =~ /world/ ; # correspond
$texte =~ /^world/ ; # ne correspond pas car « world » n'est pas au début de la chaîne

^ début de ligne

#!/usr/bin/perl -w
use strict;
# ^ début de ligne 
@tableau = ("affiche", "âme", "à toi", " affiche");
print 'regex : if ( $texte =~ m/^a/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/^a/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "(espace en-tête)";
print "\n";

rechercher en fin de chaîne : $, \Z et \z modifier

$ est l'analogue de ^ mais en fin de chaîne (ou de ligne aussi avec option m). \z est l'analogue de A en fin de chaîne, donc non affecté par l'option m. \Z est comme \z mais peut correspondre aussi à un retour à la ligne en fin de chaîne.

exemple de recherche en fin de chaîne modifier

my $texte = "Hello world!";
$texte =~ /Hello/ ; # correspond
$texte =~ /Hello$/ ; # ne correspond pas car « Hello » n'est pas en fin de chaîne

$ fin de ligne

#!/usr/bin/perl -w
use strict;

# $ fin de ligne 
@tableau = ("affiche", "affiche.", "affiches");
print 'regex : if ( $texte =~ m/che.$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/che.$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

Quantification modifier

Nous allons aborder maintenant la partie concernant l'identification d'un motif se répétant.

exemple d'introduction au quantifications modifier

Avant de commencer, il faut se confronter au problème. Nous avons une chaîne de caractères, et nous souhaitons savoir si elle contient deux fois le caractère « a ». Vu l'étendue des connaissances acquises jusque-là, nous devrions résoudre le problème comme suit :

$texte =~ /aa/; # si $texte contient 2 fois le caractère « a » il correspondra

Maintenant, on souhaite savoir si la chaîne de caractères contient deux fois le caractère « a » (jusque-là, le problème reste identique) sauf que ces deux caractères peuvent être séparés par un caractère quelconque (ou pas). Là encore, vu l'étendue des connaissances acquises actuellement, cela donnerait :

if( $texte =~ /aa/ || $texte =~ /a.a/) # pas de caractère séparateur ou un seul
{
	... # si ça correspond, on fait quelque chose
}

Nous résolvons le problème ici assez facilement, mais qu'en est-il si nous cherchons deux fois le caractère « a » avec un nombre quelconque de caractères séparateurs ? Impossible actuellement.

Quantifier par un nombre : {} modifier

Nous avons une chaîne de caractères, et nous recherchons un motif quelconque se répétant un certain nombre de fois. Nous pouvons expliciter ce nombre de fois, ou simplement donner une tranche :

 * de x à y fois : {x,y}
 * au moins x fois : {x,}

exemples avec : {} modifier

my $texte = "coucou!";
$texte =~ /c.{2}c/ ; # correspond
$texte =~ /c.{1,3}c/ ; # correspond
$texte =~ /cou{2}/ ; # ne correspond pas !
$texte =~ /c.{1,}c/ ; # correspond

Ligne 2 : il y a correspondance car nous avons précisément deux caractères séparant les deux lettres « c ». Ligne 3 : il y a correspondance là aussi, car il y a un nombre compris entre 1 et 3 caractères entre les deux lettres « c ». Attention : ligne 4 ne correspond pas car il faudrait qu'il y ait 2 lettres « u » consécutives et non toute la chaîne « cou » ! Nous verrons plus tard comment procéder pour faire cela. Enfin, ligne 5 correspond car on cherche « au moins » un caractère entre deux « c ».

Entre 0 ou 1 occurrence : ? modifier

Il est possible que le caractère (ou plus généralement le motif) soit présent ou non. On utilise pour cela le quantificateur ?.

#!/usr/bin/perl -w
use strict;

# quantificateur ?
@tableau = qw(pommes pomme mess);
print 'Test sur la regex : if ( $texte =~ m/me[s]?$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/me[s]?$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

Entre 0 ou un nombre non déterminé d'occurrences : * modifier

Quand il peut y avoir 0 ou une infinité d'occurrences d'un motif, on utilise le caractère spécial * .

#!/usr/bin/perl -w
use strict;

# *
@tableau = qw(miss mess messe messes);
print 'Test sur la regex : if ( $texte =~ m/e[s]*$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/e[s]*$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n" x 2;

# +
@tableau = qw(pomme pommes mess messe messes);
print 'Test sur la regex : if ( $texte =~ m/e[s]+$/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/e[s]+$/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

Capturer du texte modifier

La capture du texte (d'un certain motif) permet de réutiliser ce texte pour le replacer (en le modifiant éventuellement).

Simple capture de texte : () modifier

Nous souhaitons prendre une partie du texte pour le réutiliser. Lorsque vous capturez du texte, les variables $1, $2 … sont mises à jour avec la capture que vous venez de faire entre parenthèses. Ainsi, le premier groupe capturé par () pourra être réutilisé dans votre code via la variable $1, le second avec la variable $2 et ainsi de suite jusqu'à $9.

#!/usr/bin/perl -w
use strict;

# groupe de capture () avec antéréférence
@tableau = qw(dare-dare borborigme calcul barbare Tartare bébé );
print 'Test sur la regex : if ( $texte =~ m/(...)\1/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/(...)\1/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "(é = 2 octets)";
print "\n";

Ne pas capturer le motif : (?:) modifier

my $texte = "J'aime le fromage";
$texte =~ m/(?:aime).*(fromage)/;
say $1; # affiche "fromage"
#!/usr/bin/perl -w
use strict;

# non capture des 6 radicaux, réutilisation de 12 motifs sujet-suffixe
my $texte = "je chante, tu chantes, il chante, nous chantons, vous chantez, ils chantent";
    print $texte."\n";
    $texte =~ s/(\w+) (?:\w+)(\w), (\w+) (?:\w+)(\w{2}), (\w+) (?:\w+)(\w), (\w+) (?:\w+)(\w{3}), (\w+) (?:\w+)(\w{2}), (\w+) (?:\w+)(\w{3})/$1_$2 $3_$4 $5_$6 $7_$8 $9_$10 $11_$12/;
    print $texte."\n";
print "\n" x 2;

Réutiliser les motifs capturés : \1 \2 … modifier

my $texte = "J'aime le le fromage"; # doublon «le»
$texte =~ s/(\w+) \1/$1/g;
# $texte contient "J'aime le fromage" sans doublon.
# non capture du 3e, antéréférence au 6e, réutilisation de 8 motifs
my $texte = "chanter - verbe du 1e groupe - e es e ons ez ent";
    print $texte."\n";
    $texte =~ s/(\w+)(..) (?:-.*-) (\w+) (\w+) \3 (\w+) (\w+) (\w+)/je $1$3, tu $1$4, il $1$3, nous $1$5, vous $1$6, ils $1$7./;
    print $texte."\n";
print "\n";

Définir des alternatives : (a|b) modifier

#!/usr/bin/perl -w
use strict;

# "ou" inclusif |
my @tableau = qw(satin malin matin calin);
print 'regex : if ( $texte =~ m/m|t/ )'."\n";
foreach my $texte (@tableau){
    print "“$texte“";
    if ( $texte =~ m/m|t/ ){ print " vrai, "; }
    else{ print " faux, "; }
}
print "\n";

Captures avides ou non avides modifier

Le plus simple pour comprendre ce qu'est une capture avide est de prendre un exemple.

capture avide modifier

exemple 1 de capture avide modifier

Soit la capture « (c+) » qui va prendre une fois ou un nombre non limité de fois la lettre « c ».

$texte = "cccccc";
$texte =~ /^(c+)/;
say $1;

Si vous exécutez ce code, vous verrez affiché « cccccc » et non pas un seul « c ». Cela est dû à l'avidité (en anglais greedy) des opérateurs.

exemple 2 de capture avide modifier

Un autre exemple, un peu plus complexe, pour bien comprendre le phénomène, qui peut s'avérer gênant : nous avons une chaîne de caractères avec des champs délimités par des doubles points « : » :

$texte = "nom:prenom:age:date/de/naissance";
$texte =~ /^(.+):/; # .+ : on récupère le maximum de caractères avant de tomber sur un double points
say $1;

Ici, nous affichons le nom, le prénom et l'âge, car nous prenons la chaîne la plus longue possible correspondant à notre expression. C'est à dire, la chaîne la plus longue se terminant par un double point.

capture non avide modifier

Maintenant, ce qu'on voudrait c'est de ne prendre que la plus petite partie possible qui correspond à notre expression régulière. La solution est de remplacer chaque quantificateur par sa version non avide :

  • , +, ?, et {} deviennent respectivement *?, +?, ?? et {}?.
#!/usr/bin/perl -w
use strict;
# + (ou *) avide
my $texte = "anticonstitutionnellement";
$texte =~ /^(.+)i/;
print $1."\n"; # anticonstitut

# +? (ou *?) sobre
$texte =~ /^(.+?)i/;
print $1."\n"; # ant

# {…} avide
$texte =~ /^(.{6,})e/;
print $1."\n"; # anticonstitutionnellem
# {…}? sobre
$texte =~ /^(.{6,}?)e/;
print $1."\n"; # anticonstitutionn

Les coulisses des regex modifier

@+ et @- les @rchiveurs de regex modifier

@+ matrice des fins des chaînes trouvées ($+[0] fin globale, $+[1] fin de $1 …)

@- matrice des débuts des chaînes

Les items de @+ ne se notent pas @+[0], @+[1] … mais $+[0], $+[1] … car ce sont des scalaires.

#!/usr/bin/perl -w
use strict;

my $texte = "anticonstitutionnellement";
$texte =~ m/(cons....).*(nne).*(ll)/;

# les 3 correspondances (matchings) trouvées
print "$1  $2  $3\n" ; # constitu  nne  ll

# traces de la dernière recherche (double "l")
print substr($texte,0,$-[0])."  ".substr($texte,$-[0],$+[0]-$-[0])."  ".substr($texte, $+[0])."\n";

# print substr($texte,0,4)        substr($texte,4,16)                   substr($texte, 20)
#       anti                      constitutionnell                      ement
#       avant                     chaîne trouvée                        après

# variable $2
print $-[2]." ".$+[2]."\n"; # 15 18 : début & fin de "nne"

# @+ matrice des fins des chaînes $0 $1 $2 $3
print "@+\n"; # 20 12 18 20

# @- matrice des débuts des chaînes
print "@-\n"; # 4 4 15 18


Orienté Objet

Introduction modifier

Cette page sera écrite en deux parties distinctes : la définition de la programmation orientée objet en faisant abstraction d'un langage en particulier, puis comment l'utiliser dans le langage étudié.

Gardez à l'esprit que le concept de programmation orientée objet est simple, il y a juste quelques mots de jargon à connaître.

Ce qu'est la programmation orientée objet modifier

La programmation orientée objet est une manière de concevoir une application. La page wikipedia à ce sujet est bien faite, mais faisons un petit résumé pratique (et plus clair).

La POO se base sur quelques notions assez simples (rappelons que le but est de simplifier la programmation).

Les objets et leur classe modifier

Un objet est un ensemble d'attributs (variables) et de méthodes (fonctions). Une voiture par exemple pourrait se représenter par un objet « Voiture ». Elle est composée de quatre roues, un volant, quatre sièges… qui représentent autant d'attributs de l'objet. La voiture peut également se démarrer, rouler, tourner, s'arrêter… qui représentent les méthodes possibles pour cet objet.

Dans la plupart des langages, pour créer un objet et le définir, nous créons une classe (un fichier avec les différents attributs et méthodes de l'objet). À partir de cette classe, nous pouvons créer des instances. Ainsi, nous pouvons avoir autant de voitures que nous le souhaitons, qui possèdent toutes les mêmes attributs (pas forcément de même valeur cependant) et les mêmes méthodes, à partir de la classe voiture. Exemple : la classe voiture possède un attribut « couleur » et des méthodes (rouler, tourner…), nous créons deux instances de la classe voiture, une avec l'attribut « couleur » à « rouge » et l'autre à « bleue ». Les voitures sont indépendantes.

Le typage et le polymorphisme modifier

Chaque objet est un type différent (le type est le nom de sa classe). Il définit ses propres attributs et ses méthodes, et il est utile d'un point de vue sémantique dans notre code. Prenons par exemple la gestion d'un parking, on va faire entrer des « Voitures » dans ce parking, pas des entiers ou une chaîne de caractères. C'est donc une structure de données qui a un but sémantique.

Héritage et redéfinition modifier

Pour simplifier l'écriture de code (et en écrire moins), on a créé le principe d'héritage. Prenons un exemple simple : nous souhaitons gérer un jeu de courses de voitures. Nous possédons une trentaines de modèles de voitures différentes (quelques particularités qui changent), cependant elles ont toutes quatre roues, des portières etc. Pour simplifier l'écriture du code, nous allons définir ce qu'est une voiture, et dire que les différents modèles « héritent » de la classe « voiture ». Ainsi, tous les modèles possèdent de base les attributs qu'ils ont en commun, sans avoir à le dire explicitement dans chaque classe. On vient donc de factoriser grandement notre code.

Perl et la POO modifier

Perl a connu plusieurs implémentations de programmation orientée objet via différents modules. Afin d'harmoniser les pratiques, Perl6 reprend le concept de POO dans sa syntaxe de base, et ceci a été repris dans Perl5 par le module Moose. Nous allons voir comment programmer en orienté objet avec cette bibliothèque, qui s'avère de nos jours être la bonne manière de coder en POO en Perl.

Bases de POO en Perl modifier

Créer une instance : new modifier

Chaque package possède implicitement une méthode particulière (souvent appelée « new ») pour créer une instance de la classe. Nous appelons les méthodes d'un objet via l'opérateur « -> ».

use Voiture;

my $objet = Voiture->new(); # Appel d'une méthode avec l'opérateur « -> », lié à la POO

$objet est maintenant une référence à un objet « Voiture ».

Connaître la classe d'un objet : ref modifier

use Voiture;

my $objet = Voiture->new();             # Exemple précédent
say ref($objet);                                # Affiche « Voiture »

Créer et appeler une méthode : sub et -> modifier

Une méthode est une simple fonction comme nous avons déjà vu dans un chapitre précédent. Le premier paramètre est une référence à l'objet courant. Cette méthode est définie dans un « package », qui sera notre classe. Nous verrons plus loin comment créer une classe, pour voir directement la bonne manière de faire (via Moose).

Comme nous l'avons vu précédemment avec « new », pour appeler une méthode il suffit d'utiliser l'opérateur « -> ».

use Voiture; # on indique qu'on utilise la classe Voiture

my $voiture = Voiture->new();   # on crée une instance
$voiture->demarrer();                   # démarre la voiture référencée par $voiture

À remarquer : au début on utilise l'opérateur « -> » sur le package directement pour créer l'instance, après on l'utilise sur l'objet référençant l'instance pour faire appel aux méthodes liées à un objet en particulier (que l'on nomme méthodes d'instance).

POO via Moose modifier

Nous arrivons à la partie la plus intéressante. Jusque-là tout était peut-être un peu flou, mais cela va s'éclaircir !

Créer une classe modifier

Une classe se définit par un package, l'utilisation de Moose et se termine par « 1; » tout à la fin du fichier.

#!/usr/bin/env perl
package Voiture;        # on crée la classe « Voiture »
use Moose;                      # Utilisation de Moose pour créer une classe

1;                                      # Permet de s'assurer qu'une classe a bien été chargée

Difficile de faire plus simple non ? Cette classe ne contient rien de bien utile pour le moment, on ne peut que créer une instance de l'objet comme vu précédemment.

Les attributs modifier

Bases : has is isa required modifier

Un attribut est déclaré avec le mot clé has. On doit lui passer au moins un paramètre : l'option « is » qui définit si l'attribut est en lecture seule (ro pour read-only) ou s'il est en lecture et écriture (rw pour read-write).

has couleur => ( is => 'rw');

Les attributs peuvent avoir un type précis, qui se trouve dans [liste]. Nous forçons à vérifier ce type avec l'option isa.

has force => ( is => 'rw', isa => 'Int');

Nous pouvons même créer de nouveaux types mais cela va au delà du but de ce livre, veuillez vous référer à la documentation officielle du module MooseUtilTypeConstraint.

Nous pouvons décider qu'une option est obligatoire.

has couleur => ( is => 'rw', required => 1 );

Il y a d'autres options disponibles dont de très intéressantes et puissantes à découvrir dans la documentation du module [[1]], que j'encourage vivement à aller voir pour les anglophones.

Déclarer plusieurs attributs directement modifier

Petite astuce pour gagner du temps, déclarer plusieurs attributs avec les mêmes options.

has [ 'force', 'vitesse', 'endurance' ] => ( is => 'rw', isa => 'Int' ); # déclare 3 attributs de type entier en lecture et écriture
Créer l'instance en modifiant la valeur des attributs modifier

On peut choisir de modifier la valeur d'un attribut dès la création de l'instance de la classe.

my $voiture = Voiture->new(couleur => "rouge"); # l'attribut "couleur" vaut maintenant "rouge"
Récupérer et modifier la valeur d'un attribut modifier

Pour récupérer ou modifier un attribut, il faut passer par des fonctions nommées accesseurs. Pour récupérer la valeur d'un attribut il suffit d'écrire $objet->nom_attribut et pour la modifier $objet->nom_attribut("nouvelle valeur").

my $voiture = Voiture->new(couleur => "rouge"); # l'attribut "couleur" vaut maintenant "rouge"
my $couleur_voiture = $voiture->couleur;                # on récupère l'attribut "couleur" de l'instance de la classe "Voiture"
say $couleur_voiture;                   # affichera "rouge"
$voiture->couleur("bleue");             # on modifie l'attribut "couleur"
$couleur_voiture = $voiture->couleur;                   # on récupère à nouveau l'attribut (qui a été modifié)
say $couleur_voiture;                   # affichera "bleue"
Modifier les noms des accesseurs modifier

Il est possible de modifier les fonctions d'accès et de modification des attributs. Cela se fait grâce aux options reader et writer de la création d'un attribut.

package Personnage;     # on crée la classe « Personnage »
# dans cet exemple, nous modifions le nom des deux fonctions permettant l'accès en lecture et en écriture de l'attribut "nom"
has nom => ( is => rw, reader => 'obtenir_nom_personnage', writer => 'renommer_personnage' );

Une convention veut que nous nous précédions le nom de l'accesseur par un underscore ( _ ) lorsque nous ne voulons pas que les classes filles l'utilisent. Rien n'empêche en pratique leur utilisation, mais cela est à utiliser à vos risques.

Déclencheur sur la modification d'un attribut : trigger modifier

Lors la modification d'un attribut on veut avoir une fonction qui soit appelée.

Soit le fichier Personnage.pm :

package Personnage;     # on crée la classe « Personnage »
use Moose;                      # Utilisation de Moose pour créer une classe

has nom => ( 'is' => 'rw',
                trigger => \&_renommer );       # renvoie une référence vers la fonction "_renommer" de l'espace de nom courant

sub _renommer()
{
        my ($self, $nouveau, $ancien) = @_;
        say "Ancien nom : " . $ancien if @_ > 2;
        say "Nouveau nom : " . $nouveau ;
}
1;                                      # Permet de s'assurer qu'une classe a bien été chargée

Soit le fichier Jeu.pl :

use Personnage;         # pour utiliser notre module "Personnage"

my $perso = Personnage->new();
$perso->nom('Sam');
# Affichage de "Nouveau nom : Sam"
$perso->nom('Luc');
# Affichage de
#       "Ancien nom : Sam"
#       "Nouveau nom : Luc"
Références faibles : weak_ref modifier

Tout d'abord, petit point sur la façon dont Perl gère la mémoire.

En Perl, nous ne manipulons pas directement la mémoire de l'ordinateur, la gestion est déléguée directement à Perl. Quand on n'utilise plus une variable, ou un objet, il faut « libérer » la zone mémoire qu'elle occupe. Pour trouver ce qu'il faut libérer, on utilise un ramasse-miettes (Garbage Collector). Il y a différentes manières d'implémenter un ramasse-miettes, celle utilisée par Perl est le comptage de références.

Le principe est assez simple : pour chaque variable on va compter le nombre de fois qu'on a une référence qui pointe dessus, une fois qu'on n'en a plus, on ne peut plus accéder à cette zone mémoire. Par conséquent, on peut libérer la mémoire puisque la variable n’est de toutes manières plus utilisable. Pour plus d'informations, je conseille d'aller voir la page sur les ramasse-miettes sur wikipedia.

Soit le module Personnage tel que :

package Personnage;     # on crée la classe « Personnage »
use Moose;                      # Utilisation de Moose pour créer une classe

has nom => ( 'is' => 'rw' );
has [ 'papa', 'maman' ] => ( 'is' => 'rw', weak_ref => 1, isa => 'Personnage' );

1;                                      # Permet de s'assurer qu'une classe a bien été chargée

Soit le code utilisant ce module :

use Personnage;         # pour utiliser notre module "Personnage"

my $enfant = Personnage->new( nom => "Philippe");
my $papa = Personnage->new( nom => "Serge" );
$enfant->papa( $papa );

{
        my $maman = Personnage->new( nom => "Bernadette" );
        $enfant->maman( $maman );
}
# l'objet $maman n'existe plus, il n'y a plus de référence sur cette variable dans le code
say $enfant->papa->nom; # affichera "Serge"
say $enfant->maman->nom; # affichera une erreur d'exécution

Héritage : extends modifier

Comme nous avons vu en introduction de ce chapitre, l'héritage permet de créer des classes décrivant toujours un objet plus précis. Par exemple, pour un jeu vidéo on fait une classe "Personnage" puis une classe "Magicien". Un magicien est un personnage. Il hérite donc de toutes ses propriétés et en rajoute potentiellement.

Soit le module Personnage tel que :

package Personnage;     # on crée la classe « Personnage »
use Moose;                      # Utilisation de Moose pour créer une classe

has nom => ( 'is' => 'rw' );

1;                                      # Permet de s'assurer qu'une classe a bien été chargée

Maintenant on veut créer le magicien qui, en plus d'avoir un nom, pourra lancer une boule de feu. Soit le module Magicien :

package Magicien;
use strict;
use Moose;                      # Utilisation de Moose pour créer une classe
use v5.14;

extends "Personnage";   # on hérite de la classe Personnage

sub lancer_boule_de_feu() {
        my ($self) = @_;
        say "Le magicien " .
                $self->nom .    # le magicien est un personnage, donc il possède un nom
                " lance une boule de feu !";
}

Maintenant on essaie notre classe :

use Magicien;

my $magicien = Magicien->new( nom => "George" );        # soit un magicien nommé "George"

$magicien->lancer_boule_de_feu(); # affichera "Le magicien George lance une boule de feu !"

Perl permet l'héritage multiple, ce qui veut dire qu'une classe peut hériter de plusieurs autres classes, voici la syntaxe :

extends "classe1", "classe2";
Modifier une méthode héritée (surcharge) modifier

Lors d'un héritage, on souhaite parfois changer une méthode dont on hérite, cela s'appelle une surcharge. Pour cela nous n'avons qu'à recréer une méthode de même nom qui remplacera l'ancienne.

Modifier un attribut hérité : + modifier

On souhaite parfois changer une option de l'attribut, comme par exemple rendre un attribut non modifiable (ro) ou donner une valeur par défaut à un attribut, pour cela on peut modifier la définition de l'attribut. Cela se fait simplement en rajoutant un "+" devant le nom de l'attribut dans notre classe fille (celle qui hérite).

package Magicien;
use Moose;                      # Utilisation de Moose pour créer une classe
extends "Personnage";   # on hérite de la classe Personnage

has '+nom' => ( is => 'rw', default => 'Gandalf le Gris' ); # un magicien a un nom par défaut

Attention cependant, il est déconseillé de redéfinir un attribut juste pour changer sa valeur par défaut, on préfèrera donner une valeur par défaut à un attribut dans le constructeur de la classe.

Les rôles : Moose::Role with requires modifier

Un rôle n'est pas à proprement parler une classe, mais plutôt une alternative à la hiérarchie imposée par la programmation orientée objet. Si nous reprenons des exemples déjà vus : un magicien est un personnage. Un magicien peut aussi être un guérisseur (qui soigne les autres personnages) mais ce n'est pas nécessairement le cas. On peut dire qu'il remplit la fonction de guérisseur, il a ce rôle.

Un rôle est défini comme une classe, avec éventuellement des attributs et des méthodes et utilise Moose::Role en lieu et place de Moose. Ce que nous allons faire généralement avec les rôles c'est de les utiliser pour indiquer des fonctions qui doivent apparaître dans la classe qui a ce rôle. Pour cela nous utilisons le mot clé "requires".

Soit le rôle Guerisseur :

package Guerisseur;

use Moose::Role;                        # Utilisation de Moose::Role pour définir un rôle

# toutes les classes ayant comme rôle "Guerisseur"
# devront avoir une méthode "soigner"
requires 'soigner';

1;      # comme pour une classe

Notre classe Magicien :

package Magicien;
use Moose;                      # Utilisation de Moose pour créer une classe

extends "Personnage";   # on hérite de la classe Personnage
with "Guerisseur";              # on utilise le mot clé "with" pour indiquer qu'on possède un rôle

# la méthode qu'on _doit_ implémenter (rôle Guerisseur)
sub soigner() {
        my ($self, $personnage_blesse) = @_;
        say "Le magicien " . $self->nom . " soigne " . $personnage_blesse->nom ;
}

1;

Maintenant faisons un essai sur notre code :

use Magicien;   # classe définie plus haut
use Guerrier;   # classe ne faisant qu'hériter de Personnage

my $magicien = Magicien->new( nom => "George" );
my $guerrier = Guerrier->new( nom => "Jean-hubert" );

$magicien->soigner($guerrier);  # affichera "Le magicien George soigne Jean-hubert"

Un rôle ne peut pas être instancié. Si on créer des méthodes ou qu'on défini des attributs dans le rôle, alors les classes qui ont ce rôle auront aussi ces attributs et ces méthodes, comme en cas d'héritage.



Ressources

Programmation Perl
 
Programmation Perl
Sommaire




Modifier ce modèle


Liens web modifier

Livres autour de Perl modifier

  • Perl - Pocket Reference, de Johan Vromans, O'Reilly
  • Perl Moderne, de Sébastien Aperghis-Tramoni, Philippe Bruhat, Damien Krotkine, Jérôme Quelin, Pearson
  GFDL Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture.


  1. https://unicode-table.com/fr/
  2. https://docstore.mik.ua/orelly/webprog/pcook/ch13_05.htm
  3. https://www.regular-expressions.info/posixbrackets.html
  4. https://www.regular-expressions.info/unicode.html
  5. https://www.regextester.com/15
  6. Jan Goyvaerts, Steven Levithan, Regular Expressions Cookbook, O'Reilly Media, Inc., (lire en ligne)
  7. Les options sont appelées modificateurs (modifiers en anglais), voir https://www.regular-expressions.info/modifiers.html