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".
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.
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.
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.
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.
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.
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.
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 |
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 :
\d
: un chiffre, équivalent à
[0-9]
(d comme digit, chiffre en anglais)
\D
: un non-numérique,
équivalent à [^0-9]
\w
: un alphanumérique,
équivalent à [0-9a-zA-Z_]
(w comme word, c'est un caractère
d'un mot)
\W
: un non-alphanumérique,
équivalent à [^0-9a-zA-Z_]
\s
: un espacement, équivalent
à [ \n\t\r\f]
(s comme space)
\S
: un non-espacement,
équivalent à [^ \n\t\r\f]
On remarquera qu'un ensemble et son complémentaire sont notés par la même lettre, l'une est minuscule, l'autre majuscule.
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.
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).
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.
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
.
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.
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 :
m/toto/i
recherche le mot toto indifféremment en majuscules ou
en minuscules. On aurait pu écrire
m/[tT][oO][tT][oO]/
s///
effectue la transformation de la première occurrence du
motif recherché et ne va pas plus loin. Si cette option est spécifiée,
le moteur d'expressions régulières avancera dans la variable tant qu'il
pourra y faire des substitutions.
Par exemple, l'expression
$v =~ s/ +/ /g;
remplace chaque groupe de
plusieurs espaces par un seul (contrairement à un des exercices
précédents où l'expression régulière ne remplaçait que la première
occurrence du motif trouvé).
Voyez par exemple le code suivant :
$t = $s = "sd et sd"; $t =~ s/sd/toto/; # => "toto et sd" $s =~ s/sd/toto/g; # => "toto et toto"
g
est aussi utilisable en correspondance. Elle
permet à cet opérateur de fonctionner avec état, c'est-à-dire de
poursuivre sa recherche en partant du dernier motif trouvé. On
l'utilise typiquement dans une boucle ; voyez cet
exemple :
my $v = "aatobbtbvvtczz"; while( $v =~ m/t./g ) { print "$&\n"; }
to tb tc
$s =~ s/(\d+)/fonction($1)/e;
$s
par
la valeur de retour de la fonction appliquée à ce nombre.
Autre exemple, avec des options combinées celui-là :
$s =~ s/0x([0-9a-f]+)/hex($1)/gei;
$s
(la fonction "hex" est une fonction
interne perl qui fait la conversion hexadécimal vers
décimal; par exemple : hex(0xAf) renvoie 175).
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.
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") |
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).
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):
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
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.
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:
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
Voici dans le désordre quelques autres liens qui pourront vous permettre d'appronfondir le sujet:
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 |
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 |
caractère | signification |
---|---|
\t |
tabulation |
\n |
entrée |
\r |
retour chariot |
\x hh |
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 |
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 |
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
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 |