next up previous contents index
suivant: 6. Les fonctions classées monter: perl précédent: 4. Les entrées-sorties   Table des matières   Index

Sous-sections


5. Les expressions régulières

Les expressions régulières5.1 sont une des caractéristiques de perl qui rendent ce langage particulièrement adapté au traitement des fichiers texte.

Une expression régulière5.2 est une suite de caractères suivant une certaine syntaxe qui permet de décrire le contenu d'une chaîne de caractères, afin de tester si cette dernière correspond à un motif5.3, d'en extraire des informations ou bien d'y effectuer des substitutions.

5.1 La syntaxe

Elle est à la base identique à celle des expressions régulières de programmes connus comme grep, sed,... mais plusieurs nouvelles fonctionnalités ont été ajoutées. Nous allons voir ici les bases, ainsi que certaines améliorations apportées par perl.

Les opérations sur les expressions régulières sont effectuées par défaut sur la variable $_.

Pour les faire s'appliquer à une autre variable, il faut utiliser l'opérateur =~ :

if ($variable =~ /regexp/) {...};
# est donc équivalent à
$_ = $variable;
if (/regexp/) {...};

5.1.1 Les métacaractères

Chaque caractère correspond à lui-même, exception faite des métacaractères qui ont une signification particulière. Pour traiter un métacaractère comme un caractère normal, il suffit de le précéder d'un \.

Voici quelques métacaractères, avec leur signification :

^ début de chaîne. Ce n'est pas un véritable caractère ;
$ fin de chaîne. Même remarque ;
. n'importe quel caractère, excepté newline ;
| alternative (à placer entre parenthèses) ;
() groupement et mémorisation ;
[] classe de caractères.

Quelques explications sont peut-être nécessaires. Une regexp du type /a[bc]d/ correspondra aux chaînes abd et acd. [] permet d'énumérer une classe de caractères. L'interprétation de cette expression sera donc : un a, suivi d'un b ou d'un c, puis un d.

L'ensemble des caractères composant la classe peut être précisée par énumération (comme précédement) ou bien en précisant un intervalle comme par exemple /[a-z]/ qui correspondra à tous les caractères compris entre a et z.

On peut également prendre le complémentaire de cet ensemble, en le précédant d'un ^5.4. Donc /a[^bc]d/ correspondra à toutes les chaînes du type a.d, sauf abd et acd. On peut donc lire : un a, suivi d'un caractère qui n'est ni un b ni un c, puis un d.

L'alternative permet de préciser que l'on recherche l'une ou l'autre des expressions séparées par des |. Par exemple, /arti(chaut|ste)/ correspondra aux chaînes artichaut et artiste. Il est bien sûr possible de mettre plus de deux alternatives.

Enfin, la mémorisation permet de mémoriser certaines des parties de la chaîne. Par exemple, appliquer l'expression /b(.+)ars/ à la chaîne beggars mémorisera la partie qui correspond à ce qui se trouve entre parenthèses, i.e. egg, et fixera la variable $1 à cette valeur. On peut donc lire : un b, suivi d'une série (+) de caractères quelconques (.), que l'on mémorisera (les parenthèses), puis la chaîne ars.

5.1.2 D'autres caractères spéciaux

Les notations suivantes sont également utilisables (pour la plupart inspirées de la syntaxe de la fonction C printf) :

$\texttt{\symbol{92}}$t tabulation
$\texttt{\symbol{92}}$n newline
$\texttt{\symbol{92}}$r retour-chariot
$\texttt{\symbol{92}}$e escape
$\texttt{\symbol{92}}$cC contrôle-C, où C peu être n'importe caractère.
$\texttt{\symbol{92}}$s espace
$\texttt{\symbol{92}}$S non-espace
$\texttt{\symbol{92}}$w lettre (caractères alphanumériques et _)
$\texttt{\symbol{92}}$W non-lettre
$\texttt{\symbol{92}}$d chiffre
$\texttt{\symbol{92}}$D non-chiffre

5.1.3 Les quantificateurs

Différents quantificateurs s'appliquent aux caractères et métacaractères :

* apparaît 0, 1 ou plusieurs fois
+ apparaît 1 ou plusieurs fois
? apparaît 0 ou 1 fois
{n} apparaît exactement n fois
{n,} apparaît n fois ou plus
{m,n} apparaît au moins m fois, au plus n fois

Il faut savoir que ces quantificateurs sont dits gourmands. Par exemple, appliquer /a(.+)a/ à abracadabra fixera $1 à bracadabr, la plus longue chaîne possible correspondant à l'expression, et non br.

5.1.4 Les quantificateurs non-gourmands

Une nouveauté intéressante introduite dans la version 5 de perl est la possibilité d'obtenir des quantificateurs non gourmands, i.e. qui ne matchent pas la plus grande chaîne possible, en mettant un ? après le quantificateur.

Voici un exemple illustrant le caractère gourmand des expressions régulières classiques, et l'apport de perl5 dans ce domaine :

$chaine = 'Voila un <A HREF="index.html">index</A> et
une autre <A HREF="reference.html">reference</A>.';

($greedy) = ($chaine =~ /(<.+>)/);
($nongreedy) = ($chaine =~ /(<.+?>)/);

print "1: ", $greedy, "\n2: ", $nongreedy, "\n";
qui donne le résultat suivant :

1: <A HREF="index.html">index</A> et une
           autre <A HREF="reference.html">reference</A>
2: <A HREF="index.html">


5.2 Utilisation : recherche

Une des premières utilisations des expressions régulières est le matching : on peut tester si une chaîne de caractères correspond à une expression régulière, i.e. à un motif particulier.

5.2.1 Syntaxe

Pour cela, on utilise la fonction m/REGEXP/, qui s'applique par défaut à la variable $_. Si on désire l'appliquer à une autre variable, la syntaxe est la suivante:

if ($var =~ m/REGEXP/) { ... }

REGEXP est l'expression régulière dont on cherche à savoir si elle correspond à la variable $var.

On peut faire suivre cette fonction de paramètres qui modifient le comportement de la fonction de matching. Ces paramètres sont formés d'au moins un caractère parmi g, i, s, m, o, x. Voici le détail de leurs actions :

g recherche globale (recherche toutes les occurences, s'il y en a plusieurs dans la chaîne traitée)
i ne pas tenir compte de la casse des caractères (case-insensitive)
s traiter la chaîne comme une ligne simple (défaut)
m traiter la chaîne comme une ligne multiple
o ne compiler l'expression qu'une seule fois
x utiliser les expressions régulières étendues

Pour tester si la variable $var contient la chaîne foo mais sans faire de distinction majuscules/minuscules, on écrira :

if ($var =~ m/foo/i) { ... }

Le premier m de l'expression m/REGEXP/ peut être omis si le délimiteur de l'expression est un / (slash, ou barre oblique). L'utilisation du m permet d'utiliser n'importe quel caractère comme délimiteur, ce qui évite, lorsqu'il s'agit de construire une expression contenant des /, de précéder chaque / d'un $\texttt{\symbol{92}}$. Par exemple :

if ($var =~ m#^/etc#) { ... }

Les expressions régulières peuvent contenir des variables qui seront interpolées à chaque appel à l'expression. Ce comportement est utile, et intuitif, dans certaines situations mais est pénalisant du point de vue de la rapidité d'exécution. Si l'on est certain que la variable ne changera pas au cours du script, on peut ajouter le modificateur o. Mais attention, si on oublie que l'on a mis ce modificateur et que l'on modifie quand même la variable, ce changement ne sera pas pris en compte dans l'expression régulière.

5.2.2 Valeurs de retour

La valeur retournée par la fonction dépend du contexte dans lequel elle est appelée : dans un contexte scalaire, la fonction renvoie une valeur non nulle en cas de succès, et une valeur undefined dans le cas contraire.

$match = ($chaine =~ /regexp/);

Dans un contexte de liste, la fonction renvoie la liste des éléments qui ont matché les expressions entre parenthèses. Si l'expression ne correspondait pas, on obtient une liste nulle.

($href) = ($chaine =~ /<a\s+href="(.+?)">/i);

Dans tous les cas, la fonction fixera les variables $1, $2, ... avec les éléments qui ont matché les expressions entre parenthèses.


5.3 Utilisation : substitution

La syntaxe de la fonction de substitution est analogue à celle utilisée par sed, vi, ..., mises à part les quelques différences syntaxiques d'écriture des regexps. De manière analogue à la fonction de comparaison, la fonction de substitution s'applique par défaut à la variable $_. Pour la faire s'appliquer à une variable quelconque, il faut utiliser la notation :

$var =~ s/REGEXP/chaîne/egismox;

Les modificateurs qui suivent l'expression sont identiques à ceux applicables à la fonction de comparaison.

Un nouveau modificateur est disponible : e. Il précise que l'expression de remplacement est une expression à évaluer, ce qui permet d'utiliser le résultat d'une opération dans la chaîne de remplacement.

Par exemple, pour convertir des caractères du type %xxxx est un code ASCII en hexadécimal dans le caractère correspondant, il suffit d'écrire:

$chaine =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

Une petite explication ? On veut effectuer une substitution (s/.../.../) sur la variable $chaine. On cherche un caractère % suivi de deux caractères valides en hexadécimal ([a-fA-F0-9]). On mémorise ces deux caractères, dans la variable $1 puis on remplace les trois caractères (les deux mémorisés plus le % qui les précéde) par le résultat de la fonction pack("C", hex($1)), qui évalue le contenu de $1 en hexadécimal, puis affiche le caractère correspondant à cette valeur. On effectue cette opération tant qu'il reste des possibilités (le modificateur g).

Prenez votre temps pour essayer de comprendre le fonctionnement de cette expression régulière. Ensuite, essayez de comprendre les transformations qui permettent d'arriver à l'expression équivalente :

$chaine =~ s/%([a-f0-9]{2})/pack("C", hex($1))/egi;


5.4 Utilisation: translation

Voilà une dernière fonction qui est généralement associée aux expressions régulières, même si elle ne les utilise pas. Son point commun avec les fonctions précédentes est qu'il faut utiliser =~ pour préciser à quelle variable elle s'applique ($_ par défaut).

Elle a le même comportement que l'utilitaire UNIX tr. Sa syntaxe est la suivante :

$variable =~ tr/liste1/liste2/cds;

Par défaut, elle transpose chaque caractère de liste1 en le caractère correspondant de liste2. Trois modificateurs sont disponibles :

c complémente la liste liste1
d supprime les éléments de liste1 qui n'ont
pas de correspondance dans liste2
s compresse les caractères dupliqués qui sont en double

Pour supprimer par exemple tous les caractères non alphanumériques, on écrit :

$chaine =~ tr/a-zA-Z0-9.//cd;


next up previous contents index
suivant: 6. Les fonctions classées monter: perl précédent: 4. Les entrées-sorties   Table des matières   Index
Olivier Aubert 2000-06-28