Regexp - Introduction aux expressions rationnelles

Table des matières

Ce document a pour but de présenter les expressions rationnelles (encore appelées expressions régulières), ainsi que leur utilisation. Aucune connaissance préalable n'est requise pour la compréhension de ce texte. Après un bref historique sur l'apparition des expressions rationnelles et leur utilité, la syntaxe ainsi que quelques exemples simples d'utilisation seront donnés. Les lecteurs curieux pourront étendre leur connaissance des expressions rationnelles en suivant les liens indiqués en fin de document. La littérature sur le sujet étant très vaste, cette bibliographie est loin d'être exhaustive, mais indique néammoins quelques tutoriaux et manuels de référence qui représentent une bonne base pour appréhender et se familiariser avec les "regexp".

Avertissement

Je tiens à mentionner au préalable que je ne suis pas expert en expressions rationnelles. J'ai écrit ce document dans le but de donner une idée des possibilités fabuleuses qu'offrent ces outils, et de donner envie aux personnes qui les découvrent de les utiliser. Il s'agit donc plus d'une compilation de documents (les textes sont issus pour partie des 2 premières entrées de la bibliographie ainsi que des pages de manuels de perl, avec quelques exemples tirés de mon expérience), ainsi que d'un petit recensement des sources à consulter pour apprendre les expressions rationnelles.

1. Introduction

1.1 Petit historique

Les expressions rationnelles sont issues des recherches en mathématiques dans le domaine des automates [1]. Cette origine fait que les expressions mises en oeuvre s'apparentent à des expressions mathématiques, et l'on retrouve des opérateurs, des valeurs et des variables. Il s'agit d'un des langages les plus rigides syntaxiquement, ce qui signifie qu'à l'inverse de langages comme le français, les expressions régulières ne présentent aucune ambiguïté, et il n'y a donc aucune dépendance suivant le contexte d'utilisation.
C'est Ken Thompson (un des principaux créateurs du système UNIX et inventeur du langage C avec Dennis Ritchie) qui le premier a implémenté les expressions régulières en informatique dans l'éditeur qed.

1.2 Définition

Les expressions rationnelles (en anglais "regular expressions" dont l'abrégé est regexp ou regex, parfois traduites de manière erronée par expressions regulières) sont une famille de notations compactes et puissantes pour décrire certains ensembles de chaînes de caractères. Elles permettent de rechercher automatiquement des morceaux de texte ayant certaines formes, et éventuellement remplacer ces morceaux de texte par d'autres.

1.3 Implémentation

Les expressions régulières sont utilisées par un grand nombre d'éditeurs de textes et utilitaires (particulierement sous Unix), par exemple Vim, Emacs, sed ou awk. On les retrouve également dans la majorité des langages de programmation modernes, soit sous forme de bibliothèque externe, soit directement implémentées dans le langage. Perl est le plus connu et propose un support natif de ces expressions, mais on peut également citer le C, qui implémente les expressions régulières par l'intermédiaire de la bibliothèque regex [3]. Java fait de même avec l'API Regex [4], qui est fourni avec le JDK depuis sa version 1.4. On peut enfin citer les shells (Bash, Ksh, Csh et consorts...), mais beaucoup d'autres logiciels utilisent ces expressions et en faire un recensement exhaustif sort du cadre de ce document.

2. utilisation

2.1 Correspondances

Il existe deux types principaux de fonctionnalités dans les expressions régulières : la correspondance (pattern matching en anglais : pattern=motif, matching=correspondance) et la substitution.

La correspondance est le fait de tester (vérifier) si une chaîne de caractères comporte un certain motif. Par exemple, on pourrait se poser les questions suivantes et y répondre par un match : la variable $v commence-t-elle par un chiffre ? Comporte-t-elle au moins deux lettres majuscules ? Contient-elle une sous-chaîne répétée deux fois d'au moins 5 caractères ? Etc.

Sa syntaxe est la suivante : m/motif/

Le m indique que nous voulons faire un match, les slashes (/) servent à délimiter le motif recherché.

Remarque: la lettre m est facultative, et il est possible de n'utiliser uniquement que les deux slashes comme ceci : /motif/

Cette fonctionnalité nous permettra aussi d'extraire des sous-chaînes d'une variable donnée sans la modifier. Par exemple, si je veux récupérer le premier nombre que comporte $v, j'utiliserai aussi la correspondance.

2.2 Substitutions

La substitution permet de faire subir des transformations à la valeur d'une variable. Par exemple : remplacer dans la variable $v toutes les sous-chaînes toto par titi. Supprimer de $v tous les mots entre guillemets. Etc.

Sa syntaxe est la suivante : s/motif/chaîne/

Le s indique que nous voulons faire une substitution, les slashes (/) servent à délimiter le motif recherché ainsi que la chaîne de remplacement.

2.3 Lien

Pour "lier" une variable à une telle expression, il faut utiliser l'opérateur =~ (dit bind en anglais).

$v =~ m/sentier/ vérifie si la variable $v comporte le mot sentier. On dit alors que la variable est "liée" à l'expression régulière. Cette expression vaut vrai ou faux ; nous l'utiliserons donc très souvent dans une structure de contrôle de type if :

if( $v =~ m/sentier/ )
{
   instructions
}

Dans les cas où le test est vrai, c'est-à-dire si la variable contient le motif (ici si $v contient sentier), les instructions seront exécutées.

De la même façon,

$v =~ s/voiture/pieds/;

remplace la première occurrence de voiture dans la variable $v par pieds (on verra plus loin comment remplacer toutes les occurrences). Le reste de $v n'est pas modifié. Le point-virgule indique la fin de l'instruction.

Pour la correspondance, il existe aussi l'opérateur !~ qui équivaut à =~ suivi d'une négation de l'expression.

if( $w !~ m/pieds/ ) { ... }

est plus concis et est équivalent à

if( ! ( $w =~ m/pieds/ ) ) { ... }

Les instructions sont exécutées si $w ne contient pas la chaîne pieds.

2.4 Motifs

Dans cette sous-partie et dans les suivantes, nous allons voir quels sont les motifs utilisables dans les expressions régulières.

Dans le cas général, un caractère vaut pour lui même ; comprenez que lorsque l'on utilise l'expression régulière m/a/ on vérifie si la variable (ici non citée) contient le caractère a. Cela semble évident, mais il est bon de le dire.

En effet, pour certains caractères spéciaux, cela n'est pas le cas. Ces caractères ont un rôle particulier dans les expressions régulières (nous allons voir cela dans la suite). Si vous avez besoin de rechercher ces caractères, il faut donc les déspécifier au moyen d'un anti-slash (\). Voici la liste de ces caractères spéciaux : \ | ( ) [ ] { } ^ $ * + ? .

Les caractères spéciaux habituels peuvent être utilisés ; en voici quelques exemples  (seuls les plus utiles sont présentés ici):

Motif Caractère
\n saut de ligne
\r retour chariot
\t tabulation
\f saut de page
\e échappement

2.5 Ensembles

Le caractère . (point) correspond à n'importe quel caractère, sauf \n (ce comportement peut être changé : nous verrons cela plus loin). Cela signifie qu'à l'emplacement de ce point dans le motif pourra (devra) correspondre un caractère quelconque. Par exemple, le motif m/t.t./ reconnaîtra toute variable comportant une lettre t suivie d'un caractère quelconque, puis une autre lettre t, puis un autre caractère quelconque ; ainsi toute variable comportant une des chaînes suivantes correspondra au motif : tata, t%tK, tot9 ...

Vous comprenez pourquoi il faut déspécifier le caractère point avec un anti-slash si vous voulez chercher un point littéral : sans cela un point matche avec n'importe quel caractère.

Le motif [caractères] matche un caractère parmi ceux présents entre crochets. Par exemple [qwerty] peut reconnaître une de ces six lettres. Le motif m/t[oa]t[ie]/ reconnaîtra toute variable comportant une des quatre chaînes suivantes : toti, tati, tote ou tate. On comprendra aisément que si un caractère est présent plusieurs fois dans cette liste, cela a le même effet que s'il était présent une seule fois : [aeiouyie] est équivalent à [aeiouy].

Il est possible de définir des intervalles de caractères dans ces ensembles. Par exemple a-z équivaut aux 26 lettres minuscules de l'alphabet. Ainsi, [2a-zR] entrera en correspondance avec toute lettre minuscule ou bien avec le 2 ou bien avec le R majuscule. On peut aussi utiliser les ensembles A-Z ou 0-9 ; par extension tout intervalle est envisageable, par exemple R-Z ou toute autre combinaison tant que le numéro ASCII du premier caractère est inférieur à celui du second (voir tableau des numéros ASCII en annexe).

Un intervalle peut prendre place au milieu d'un motif quelconque : m/tot[a-zA0-9]V/ matche totaV, totbV ... totzV, totAV, tot0V ... tot9V.

Remarques:
1. Si le caractère tiret (-) doit être présent dans l'ensemble, il faut le mettre en première ou en dernière position afin de lever toute ambiguïté possible avec un intervalle. Par exemple [a-z4-] matche soit une minuscule, soit un 4, soit un tiret.

2. Le caractère ^ (accent circonflexe) a un rôle particulier s'il est placé en début d'intervalle ; il prend le complémentaire de l'ensemble, il faut le lire "tout caractère sauf ...". Par exemple [^ao] matche tout caractère sauf le a et le o. Le motif [^0-9] matche tout caractère non numérique.

Ci-dessous sont mentionnés quelques raccourcis pour des ensembles courants :

On remarquera qu'un ensemble et son complémentaire sont notés par la même lettre, l'une est minuscule, l'autre majuscule.

2.6 Quantificateurs

 

Les quantificateurs s'appliquent au motif atomique (c'est-à-dire le plus petit possible) le précédant dans l'expression régulière. Ils permettent de spécifier un nombre de fois où ce motif peut/doit être présent.

Par exemple l'étoile * indique que le motif peut être présent zéro fois ou plus : m/a*/ se met en correspondance avec le mot vide, avec a, aa, aaa, aaaa ...

Quand je dis qu'un quantificateur s'applique au motif atomique le plus petit possible, je veux dire par là que dans l'expression régulière m/za*/ l'étoile s'applique uniquement à la lettre a et non au mot za.

Il est par ailleurs important de noter qu'un tel quantificateur est par défaut gourmand, c'est-à-dire qu'il se met en correspondance avec le plus de caractères possible dans la variable liée. Cela a son importance dans le cas d'une substitution : si la variable $v contient la chaîne vbaaal, et si on effectue l'instruction suivante : $v =~ s/ba*/hello/; la chaîne matchée par la première expression ba* sera baaa (le quantificateur matche le plus de caractères possible) et la substitution aura pour effet de donner pour valeur vhellol à la variable $v.

Voici un tableau des quantificateurs :

  le motif présent exemple mots matchés
* 0 fois ou plus m/a*/ mot vide, a, aa, aaa ...
+ 1 fois ou plus m/a+/ a, aa, aaa ...
? 0 ou 1 fois m/a?/ mot vide ou a
{n} n fois exactement m/a{4}/ aaaa
{n,} au moins n fois m/a{2,}/ aa, aaa, aaaa ...
{,n} au plus n fois m/a{,3}/ mot vide, a, aa ou aaa
{n,m} entre m et n fois m/a{2,5}/ aa, aaa, aaaa ou aaaaa

On remarquera que * est un raccourci pour {0,} ainsi que + pour {1,}, de même que ? pour {0,1}.

Dans les exemples précédents, tous les quantificateurs sont appliqués à un caractère. On peut les appliquer à tout motif, par exemple à un ensemble : m/[0-9-]{4,8}/ recherche une chaîne comportant entre 4 et 8 caractères numériques ou tirets contigus.

2.7 Alternatives

Il est possible d'avoir le choix entre des alternatives ; il faut pour cela utiliser le signe pipe (|) : l'expression m/BIA|CLY|FSC|AJA/ reconnaît les mots comportant soit BIA, soit CLY, soit FSC, soit AJA (vous aurez reconnu les aéroports de la Corse).

2.8 Assertions

Une assertion marque une position dans l'expression, elle ne correspond à aucun caractère.

Par exemple, l'accent circonflexe (^) correspond au début de la chaîne. L'expression $v =~ m/^a/ est vraie si la variable $v commence par la lettre a.

Le signe ^ a donc plusieurs rôles. S'il est au début d'un ensemble entre crochets, il permet d'en prendre le complémentaire ; s'il est au début de l'expression régulière, il marque le début de la chaîne. On veillera à ne pas les confondre.

Le dollar ($) correspond à la fin de la chaîne. L'expression $v =~ m/c$/ est vraie si la variable $v se termine par la lettre c.

Ces deux assertions sont les plus courantes. Il en existe d'autres dont \b qui marque un début ou une fin de mot . Par exemple m/\btoto\b/ matche "toto", "toto autreMot", "unMot toto autreMot", etc. mais pas "unMot totoMotCollé" car le deuxième \b ne peut pas être vrai entre la lettre o et la lettre M.

2.9 Mémorisation

Le regroupement au moyen des parenthèses est dit mémorisant. Cela signifie que l'expression matchée par ce regroupement est gardé en mémoire par le moteur d'expressions régulières et qu'elle pourra servir à nouveau dans la suite de l'expression.

Ces variables spéciales $1, $2 etc. sont aussi accessibles après l'expression régulière (jusqu'à la fin du bloc courant ou une autre expression régulière). Elles correspondent bien sûr aux sous-chaînes matchées entre parenthèses. Nous pouvons nous en servir pour extraire certaines sous-chaînes et les utiliser ensuite.

Pour donner un exemple simple, supposons que nous voulions extraire les noms et prénoms d'une personne à partir de son adresse mail, qui est de la forme:

        prenom.nom@domaine.ext

Nous allons utiliser l'expression rationnelle suivante:

	/\b(\w+)\.(\w+)@\w+\.w{2,4}\b/
            ^^^    ^^^ 
             $1     $2

De cette manière, le prénom de la personne est stocké dans la variable $1, et son nom dans la variable $2.

2.10 Substitution de variables

Il est tout à fait possible de mettre une variable dans un motif d'une expression régulière. Cette variable sera substituée par son contenu. Par exemple :

$s = "velo";
if( $v =~ m/$s/ ) { ... }
    

La variable sera substituée et la recherche s'effectuera sur le mot velo.

Notez cependant que si la variable substituée contient des caractères spéciaux au sens des expressions régulières, ils seront vus comme tels. Si dans notre exemple, la variable $s avait pour valeur la chaîne "ve(lo", le moteur d'expression régulière nous signalerait une erreur due à la parenthèse ouvrante qui n'est pas refermée, exactement comme si nous avions écrit :

if( $v =~ m/ve(lo$/ ) { ... }  # incorrect

Cela peut aussi poser des problèmes de sécurité si le programmeur ne sait pas ce que peut contenir la variable substituée (par exemple si sa valeur provient de l'utilisateur). Il existe pour cela une fonction quotemeta qui prend en paramètre une chaîne de caractères et renvoie cette même chaîne en ayant déspécifié les caractères spéciaux.

$s = "fds(ds";
$s2 = quotemeta($s);
print "$s2\n";   # affiche  fds\(ds
if( $v =~ m/$s2/ ) { ... }

Pensez à toujours utiliser cette fonction lorsque vous voulez placer une variable dans un motif ; cela résout bien des problèmes.

3. Options

Après le dernier séparateur des opérateurs de correspondance (m ou rien) ou de substitution (s) il est possible d'indiquer une ou plusieurs options. Les syntaxes sont donc : m/motif/options et s/motif1/motif2/options

Les options permettent de modifier le comportement du moteur d'expressions régulières. Voici la liste de quelques options parmi les plus utiles :

4. Quelques exemples

Le tableau ci-dessous réunit quelques exemples simples d'utilisation des expressions rationnelles. Vous pouvez vous entraîner en cachant la partie droite du tableau et en essayant de découvrir par vous même la signification des motifs indiqués dans la partie gauche du tableau.
Vous trouverez également à la suite quelques solutions un peu plus évoluées à certains problèmes concrets que j'avais rencontrés quand je travaillais à Air France.

4.1 Petits exercices

motif matche avec...
abc abc (cette séquence exacte, mais n'importe où dans la chaîne)
^abc abc en début de chaîne
abc$ abc en fin de chaîne
a|b soit a, soit b
^abc|abc$ la chaîne abc en début ou en fin de chaîne
ab{2,4}c un a suivi de deux, trois ou quatre b, suivi par un c
ab{2,}c un a suivi par au moins deux b, suivi par un c
ab*c un a suivi par n'importe quel nombre (zéro ou plus) de b, suivi par un c
ab+c un a suivi par un ou plusieurs b, suivi par un c
ab?c un a suivi par un b (mais celui-ci est facultatif), suivi par un c; cela matche donc soit avec abc, soit avec ac
a.c un a suivi par un caractère quelconque (sauf un retour à la ligne), suivi par un c
a\.c a.c
[abc] a, b ou c
[Aa]bc Abc ou abc
[abc]+ n'importe quelle chaîne comportant des a, b ou c (comme a, abba, acbabcacaa)
[^abc]+ n'importe quelle chaîne qui comporte ni des a, ni des b ni des c (comme defg)
\d\d deux chiffres, comme 42; on aurait pu l'écrire également \d{2}
\w+ un "mot": une séquence non-vide de caractères alphanumériques, comme toto ou 12titi8 ou encore tata_1
100\s*mk les chaînes 100 et mk séparés optionnellement par n'importe quel nombre de blancs (espaces, tabulations ou retour chariots)
abc\b abc suivi d'une bordure de mot (i.e. abc mais pas abcd)
perl\B perl lorsqu'il n'est pas suivi par une bordure de mot (i.e. "perldoc" mais pas "perl c'est bien")

4.2 Cas concrets

Voici deux exemples de problèmes que j'ai rencontrés à Air France, qui ont pu être résolus grâce à un one-liner Perl (voir en annexe pour une présentation rapide des one-liners).

4.2.1 Substitution des codes aéroports en codes villes

La problématique consistait à modifier tous les fichiers d'un même répertoire, en remplaçant les codes aéroports parisiens par le code ville PAR. Il était également nécessaire de faire une sauvegarde des fichiers d'origine.

La première étape de la résolution consiste à enregistrer dans une variable toutes les chaînes à repérer dans les fichiers, c'est-à-dire les différents identifiants des aéroports parisiens. On définit également le code ville de Paris qui remplacera ces codes aéroport:

        $aero = "CDG|ORY|LBG"; $ville = "PAR";

Remarque: Ces définitions seront insérées au début de l'expression, à l'intérieur d'une balise BEGIN{}. Cela permettra de définir ces deux variables avant d'effectuer la boucle sur toutes les lignes du fichier. Si ces déclarations ne sont pas mises dans une balise BEGIN, alors on réassignera les deux variables à chaque nouvelle ligne du fichier, ce qui sera plus gourmand en ressources.

Ensuite, on construit le motif de l'expression rationnelle qui va effectuer les substitutions:

        s/\b$aero\b/$ville/g

Nous utilisons les \b pour bien identifier les codes aéroports, et ne pas prendre en compte les mots qui contiendraient les chaînes CDG, ORY ou LBG mais qui ne seraient pas des aéroports. Le g en fin d'expression est utile dans le cas où on trouve plusieurs codes aéroports sur une même ligne: ils seront ainsi tous remplacés par le code ville. Si il est omis, alors uniquement le premier code aéroport d'une ligne sera remplacé, pas les suivants.

Pour que les fichiers qui ont suivi une modification soient automatiquement sauvegardés, on utilisera l'option -i de Perl, et on renommera les fichiers sauvegardés en rajoutant l'extension .orig derrière leur nom:

        perl -i.orig

Enfin, il ne reste plus qu'à utiliser l'option -p pour parcourir toutes les lignes du fichier ouvert. Pour lire successivement tous les fichiers d'un répertoire, on lancera la commande en indiquant * comme nom de fichier, ce qui sélectionne tout ce qui se trouve dans le répertoire courant. On n'oubliera pas l'option -e qui indique que l'on lance une commande Perl en ligne.

Cela nous donne donc au final: (nous n'écrivons pas sur une seule ligne pour des questions de mise en page, donc nous mettons un "\" pour indiquer à l'interpréteur que notre commande se continue sur la ligne du dessous):

perl -i.orig -pe 'BEGIN{$aero="CDG|ORY|LBG";$ville="PAR"} \
	s/\b$aero\b/$ville/g' *
	

4.2.2 Comptage des vols Corse-Paris

Cette fois-ci, nous allons nous intéresser aux vols Air France qui partent de Paris pour aller en Corse ou inversement. Pour simplifier la problématique et ne pas introduire de nouvelles notions, nous nous attacherons uniquement à compter les vols correspondant à ces critères dans un fichier relativement gros, qui a une structure fixe. Chaque ligne correspond à un vol, le code compagnie se trouvant dans les deux premières colonnes. Vient ensuite plusieurs informations, comme le numéro de vol, la date, ... Ces différentes informations sont codées précisément sur 17 caractères. Viennent ensuite le code aéroport de départ, puis un espace, et le code aéroport d'arrivée.

Pour construire l'expression rationnelle qui va nous permettre de séléctionner les vols, nous allons définir les aéroports concernés, de la même manière que précédemment dans une balise BEGIN{}:

        BEGIN{ $paris = "CDG|ORY"; $corse = "BIA|CLY|FSC|AJA" }

Nous aurons également besoin d'initialiser un compteur à 0 à l'intérieur de cette balise, afin de comptabiliser le nombre de vol. Pour être original, nous appelerons ce compteur i. De la même manière qu'avec la balise BEGIN, nous avons la possibilité d'executer des commandes après la boucle qui parcours l'ensemble des lignes du fichier. Il faut pour cela insérer ces commandes dans une balise END. Dans notre cas, il s'agira d'imprimer la valeur de notre compteur i une fois le comptage terminé:

        END{print "le nombre de vols PARIS-CORSE est: $i"}

Nos variables étant posées, nous aurons besoin ensuite d'incrémenter le compteur lorsque nous détecterons un vol Paris-Corse. La syntaxe pour incrémenter est la même qu'en C, et pour ajouter 1 à notre variable i, il suffit d'écrire: $i++;

Commençons maintenant à écrire notre expression rationnelle. Nous allons détecter en premier lieu les vols Air France, c'est-à-dire les lignes commençant par le code AF: /^AF/. Viennent ensuite 17 caractères: /^AF.{17}/, et enfin les codes aéroport séparés par un blanc. Ce qui nous donne:

        /^AF.{17}$paris.$corse/

Par contre, comme il s'agit des vols à destination ou en provenance de la Corse, on peut simplement prendre le symétrique de cette expression:

        /^AF.{17}$paris.$corse/ || /^AF.{17}$corse.$paris/

Dans l'expression précédente, le signe || veut simplement dire "ou".

Voilà, nous avons maintenant tous les éléments pour construire notre one-liner:

  perl -pe 'BEGIN{$paris="CDG|ORY";$corse="BIA|CLY|FSC|AJA";$i=0;}\
     $i++ if ( /^AF.{17}$paris.$corse/ || /^AF.{17}$corse.$paris/) \
     END{print "le nombre de vols PARIS-CORSE est: $i}' mon_fichier.txt 

5. Aller plus loin...

Vous vous en serez certainement rendu compte, il n'est pas facile de retenir tous ces signes cabalistiques... De plus, ce document n'aborde qu'une infime partie de tout ce qu'il est possible de réaliser avec les expressions rationnelles. Pour continuer à explorer le sujet, voici une liste de liens qui pourront être utiles.

5.1 Manuels en ligne

Les aides en ligne de Perl sont très complètes et didactiques. La majorité des questions que l'on pourrait se poser trouvent une réponse dans ces pages de manuel. Pour ceux qui ne sont pas habitués aux commandes UNIX, il faut taper la commande man suivi du nom du manuel pour accéder à celui-ci. Je vous conseille de lire dans l'ordre les manuels suivants:

[1] perlrequick
(courte introduction)

[2] perlretut
(tutoriel qui présente le sujet plus en détails)

[3] perlfaq6
questions fréquemment posées sur les expressions rationnelles

[4] perlre
(la référence complète)

[5] perlreref
(résumé des commandes les plus couramment utilisées)

Remarque: Toutes ces pages de manuel sont livrées avec Perl 5.8.6, mais il est possible que toutes n'aient pas encore été implémentées dans les versions précédentes de Perl. Si votre installation de Perl ne présente pas certaines pages de manuels cités plus haut, vous pourrez les retrouver en ligne et traduites en français à l'adresse suivante :
http://perl.enstimac.fr/DocFr.html

5.2 Pages web

Voici dans le désordre quelques autres liens qui pourront vous permettre d'appronfondir le sujet:

[1] http://regex.info

[2] http://perl.com

[3] http://www.mongueurs.net

Bibliographie

[1] http://fr.wikipedia.org/wiki/Expressions_rationnelles

[2] Linux Dossier n°2: Perl - un guide complet pour débuter et progresser - Diamond Editions - Avril/Mai/Juin 2004.

[3] http://ftp.gnu.org/pub/gnu/regex/

[4] http://java.sun.com/developer/technicalArticles/releases/1.4regex/index.html

Annexes

A. Aide mémoire

A.1 Métacaractères

caractère signification
^ début de la chaîne
$ fin de la chaîne
. n'importe quel caractère sauf retour à la ligne
* matche 0 ou plusieurs fois
+ matche au moins 1 fois
? matche 0 ou 1 fois
| alternative
() groupement; mémorisation
[] jeu de caractères
{} répétition

A.2 Répétition

caractère signification
a* zéro ou plusieurs a
a+ un ou plusieurs a
a? zéro ou un a
a{m} exactement m a
a{m,} au moins m a
a{m,n } au minimum m et au maximum n a

A.3 Notations spéciales avec \

caractère signification
\t tabulation
\n entrée
\r retour chariot
\xhh caractère hh encodé en hexadécimal
\b bordure de mot
\B pas en bordure de mot
\w matche n'importe quel caractère classifié comme "mot" (i.e. un alphanumérique ou _)
\W matche n'importe quel non-caractère
\s matche n'importe quel espace (blanc, tabulation, nouvelle ligne)
\S matche n'importe quel caractère qui n'est pas un espace
\d matche un chiffre (équivalent à [0-9])
\D matche tout sauf un chiffre

A.4 Ensembles [...]

caractère signification
[caractères] matche n'importe quel caractère de la séquence
[x-y] matche n'importe quel caractère compris entre x et y (inclus) dans l'encodage ASCII
[\-] matche le caractère - (moins)
[\n] matche le retour à la ligne
[^texte] matche n'importe quel caractère sauf ceux indiqués à la suite de l'accent circomflexe

B. Perl one-liner

Le terme "one-liner" peut être traduit par uniligne, et caractérise un programme Perl qui ne contient qu'une seule ligne de code. Les concepteurs de ce langage ont prévu quelques options intéressantes qui permettent de condenser un nombre d'instructions impressionnant sur une seule ligne.

Pour avoir la liste complète de ces options, il faut consulter la page de manuel perlrun. La fin de la page perlfaq3 présente également des exemples d'unilignes qui donnent une bonne idée de la manière dont on peut les utiliser. Je reporte ici les options les plus courantes :

-e est le paramètre principal pour l'écriture d'un uniligne. Son argument est une ligne de code.

Exemple :

    $ perl -e 'print "Hello, world!\n"'
    Hello, world!

Les deux options suivantes sont probablement les plus utilisées pour l'écriture d'unilignes en Perl.

-n ajoute la boucle suivante autour de votre code :

    LINE:
    while (<>) {
        ...    # votre programme ici
    }

-p ajoute la boucle suivante, qui imprime automatiquement les lignes, autour de votre code :

    LINE:
    while (<>) {
        ...    # votre programme ici
    } continue {
        print or die "-p destination: $!\n";
    }

Ces deux options permettent donc de boucler automatiquement sur toutes les lignes du fichier spécifié, -p rajoutant l'affichage des lignes traitées.

Remarques:
1. Avec -n et -p, si Perl n'arrive pas à ouvrir l'un des fichiers dont le nom a été passé en ligne de commande, il affiche un avertissement et passe au fichier suivant.

2. Des blocs BEGIN  et END  peuvent être utilisés pour prendre le contrôle avant et après la boucle implicite.

3. Notez également que -n et -p peuvent bien sûr être utilisés sur la ligne shebang (#!/usr/bin/perl au début de votre script), et feront ainsi une boucle implicite autour de l'intégralité de votre script.

-i vous permet de faire de l'édition sur place, c'est-à-dire de modifier directement le fichier que vous êtes en train de traiter. Ou plus exactement, le fichier traité par la construction <> (qui est justement la construction utilisée implicitement par -p et -n).

    $ perl -i -pe 's/\bfoo\b/toto/g;s/\bbar\b/titi/g' monfichier

Si vous avez peur de vous tromper, vous pouvez fournir une extension à l'option -i, qui sera utilisée pour créer un fichier de sauvegarde identique au fichier traité original. L'extension est ajoutée à la fin du nom du fichier traité :

    $ ls
    monfichier
    $ perl -i.bak -pe 's/\bfoo\b/toto/g;s/\bbar\b/titi/g' monfichier
    $ ls
    monfichier
    monfichier.bak

C. Encodage ASCII

 0 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 NUL 
 SOH 
 STX 
 ETX 
 EOT 
 ENQ 
 ACK 
 BEL 
 BS 
 HT 
 LF 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 VT 
 FF 
 CR 
 SO 
 SI 
 DLE 
 DC1 
 DC2 
 DC3 
 DC4 
 NAK 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 SYN 
 ETB 
 CAN 
 EM 
 SUB 
 ESC 
 FS 
 GS 
 RS 
 US 
 space 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 ! 
 " 
 # 
 $ 
 % 
 & 
 ' 
 ( 
 ) 
 * 
 + 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 , 
 - 
 . 
 / 
 0 
 1 
 2 
 3 
 4 
 5 
 6 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 7 
 8 
 9 
 : 
 ; 
 < 
 = 
 > 
 ? 
 @ 
 A 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 B 
 C 
 D 
 E 
 F 
 G 
 H 
 I 
 J 
 K 
 L 
 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 M 
 N 
 O 
 P 
 Q 
 R 
 S 
 T 
 U 
 V 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 W 
 X 
 Y 
 Z 
 [ 
 \ 
 ] 
 ^ 
 - 
 ' 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 a 
 b 
 c 
 d 
 e 
 f 
 g 
 h 
 i 
 j 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 k 
 l 
 m 
 n 
 o 
 p 
 q 
 r 
 s 
 t 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 u 
 v 
 w 
 x 
 y 
 z 
 { 
 | 
 } 
 ~ 
127 DEL