Perl has often been tagged as a language in which it's easy to write programs that are difficult to read, and it's no secret that regular expression syntax that has been the chief culprit. Funny that other languages have been borrowing Perl's regular expressions as fast as they can...
-- Larry Wall, Apocalypse 5
expressions rationnelles
regular expressions => regexp
=> expressions régulières
théorie des automates et langages formels
grammaires de recherche de correspondances
NFA : nondeterministic finite automaton
DFA : deterministic finite automaton
UNIX : qed
, ed
, grep
POSIX regex
Perl 5, PCRE
Perl 6
correspondance de caractères
motif composé de :
caractères normaux
"Hello World" =~ /World/; # correspond
"Hello World" =~ /lo Wo/; # correspond aussi
"That hat is red" =~ /hat/; # le "hat" de "That" correspond
correspondance de caractères
motif composé de :
caractères normaux
méta-caractères : {}[]()^$.|*+?\
"2+2=4" =~ /2+2/; # ne correspond pas "2+2=4" =~ /2\+2/; # correspond
"/usr/bin/perl" =~ /\/usr\/bin\/perl/;
"/usr/bin/perl" =~ m{/usr/bin/perl};
correspondance de caractères
motif composé de :
caractères normaux
méta-caractères : {}[]()^$.|*+?\
séquences d'échappement
"1000\t2000" =~ /00\t20/; # correspond
"cat" =~ /\143\x61\x74/; # correspond aussi (même si c'est bizarre)
ensemble de caractères possible pour un emplacement de caractère
notées par [...]
/[bcr]at/; # cherche "bat", "cat", "rat"
/[yY][eE][sS]/; # cherche "yes", "Yes", YES", etc
/yes/i; # pareil, mais plus lisible
ensemble de caractères possible pour un emplacement de caractère
notées par [...]
intervalles de caractères
/[0-9]/; # équivalent à /[0123456789]/
/[a-z]/; # équivalent à /[abcde...xyz]/
/[0-9a-fA-F]/; # chiffre hexadécimal
/item[0-9]/; # correspond à "item0", "item1"...
ensemble de caractères possibles pour un emplacement de caractère
notées par [...]
intervalles de caractères
négation de classe : [^...]
/[^0-9]/; # cherche un caractère qui n'est pas un chiffre
classes prédéfinies :
.
: tout caractère sauf \n
\d
: chiffre décimal
\w
: caractère de mot (alphanumérique plus _
)
\s
: espace normale, tabulation, saut de ligne
\h
: espace horizontal
\v
: espace vertical
\R
: saut de ligne
classes négatives prédéfinies :
\D
: ce qui n'est pas un chiffre décimal
\W
: ce qui n'est pas un caractère de mot
\S
: ce qui n'est pas un espace usuel
\H
: ce qui n'est pas un espace horizontal
\V
: ce qui n'est pas un espace vertical
exemples :
/\d\d:\d\d:\d\d/; # format d'heure hh:mm:ss
/[-+]\d/; # correspond à +2, -3, etc
/end\./; # correspond à "end." /end[.]/; # pareil
pour ancrer la recherche dans certains points
^
: en début de chaine
"beausoleil" =~ /^soleil/; # ne correspond pas
pour ancrer la recherche dans certains points
^
: en début de chaine
$
: en fin de chaine
"beausoleil" =~ /beau$/; # ne correspond pas
"beausoleil" =~ /soleil$/; # correspond
"beausoleil\n" =~ /soleil$/; # correspond aussi
pour ancrer la recherche dans certains points
^
: en début de chaine
$
: en fin de chaine
\b
: frontière de mot, intervient entre \w
et \W
"beausoleil" =~ /\bbeau/; # correspond
"beausoleil" =~ /\bbeau\b/; # ne correspond pas
"beausoleil" =~ /\bsoleil/; # ne correspond pas
répétition d'un sous-motif
*
: zéro ou plusieurs fois
+
: une ou plusieurs fois
?
: zéro ou une fois
{n}
: exactement n fois
{n,}
: au moins n fois
{n,m}
: entre n et m fois
exemples :
"kraaack" =~ /kra+ck/; # correspond
"kraaack" =~ /kra{1,}ck/; # correspond aussi
"kraaack" =~ /kra{5,}ck/; # ne correspond pas
/\w+\d{2}/; # "item04", "machine42", "Kevin68", etc
/\d+\.\d+\.\d+\.\d+/; # recherche simple d'une adresse IPv4
/<[-.\w]+\@[-.\w]+>/; # recherche simple d'une adresse mail
"aaaa" =~ /a+/; # correspond avec "aaaa"
quantifieurs non avides :
*?
: zéro ou plusieurs fois, au plus tôt
+?
: une ou plusieurs fois, au plus tôt
??
: zéro ou une fois, au plus tôt
{n}?
: exactement n fois, au plus tôt
{n,}?
: au moins n fois, au plus tôt
{n,m}?
: entre n et m fois, au plus tôt
exemples :
"aaaa" =~ /a+?/; # correspond avec "a"
"aaaabbbb" =~ /a+?b*?/; # correspond avec "a"
"aaaabbbb" =~ /a+?b+?/; # correspond avec "aaaab"
quantifieurs possessifs (nouveauté de Perl 5.10 et PCRE 7)
*+
: zéro ou plusieurs fois, et ne rend jamais
++
: une ou plusieurs fois, et ne rend jamais
?+
: zéro ou une fois, et ne rend jamais
{n}+
: exactement n fois, et ne rend jamais
{n,}+
: au moins n fois, et ne rend jamais
{n,m}+
: entre n et m fois, et ne rend jamais
exemples :
"aaaa" =~ /a+a/; # /a+/ correspond avec "aaa"
"aaaa" =~ /a+?a/; # /a+?/ correspond avec "a"
"aaaa" =~ /a++a/; # ne correspond pas
résumé :
"Lorem ipsum dolor sit amet" recherche avide : <<--| <<--| <<--| <<<<<--| recherche non-avide : |--->>> |---> |--->> |---> recherche possessive : |---| |---| |---| |------|
pour grouper des sous-motifs : (...)
par défaut, groupes capturant
référencées par \1
, \2
... dans le motif
référencées par $1
, $2
... à l'extérieur du motif
groupes non-capturant : (?:...)
exemples :
/(\w+\d+ )+/; # "item04 machine42 Kevin68 "
/(?:\d+\.){3}\d+/; # recherche simple d'une adresse IPv4
/((?:\d+\.){3}\d+)/; # recherche simple d'une adresse IPv4
/(\w+) +\1/; # recherche d'un mot répété
disjonction de sous-motifs au sein d'un groupe
exemple :
/^(add|del|list) +(addr|route|rule|table) .../ # "add addr ..." # "del rule ..." # "list route ..."
problème de la numérotation des captures
/ ( a ) (?: x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 3 4 5 6 7
remise à zéro de branche : (?|..)
numérote les captures des branches d'une alternative comme s'il n'y en avait qu'une seule
# before ------------branch-reset------------- after / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 2 3 2 3 4
nouvelle syntaxe de référencement : \g{N}
N positif : numéro de capture usuel
N négatif : référencement arrière relatif
\g{-1}
== précédente capture
exemple
my $find_dup = qr/ (\w+) \s+ \g{-1} /x;
(?<name>pattern)
pour nommer une capture
\k<name>
, \k{name}
ou \g{name}
pour s'y référer
exemple en Perl :
my $find_dup = qr/ (?<dup_word>\w+) \s+ \k<dup_word> /x;
variables lexicales %+
et %-
$+{name}
== \g{name}
$-{name}
== référence vers un tableau de toutes les captures de ce nom
Tie::Hash::NamedCapture
pour avoir des noms plus clairs
m//
- recherche de correspondances
$text = "whack zlott ooooff kraaack zzzzzwap"; $text =~ /(kra+ck)/; print $1; # "kraaack"
$line = "peer_list = host1 host2 host3"; $line =~ m/^(\w+) *= *(.*)$/; print $1; # "peer_list" print $2; # "host1 host2 host3"
s///
- recherche et remplacement
$source =~ s/OpenOffice.org/LibreOffice/g;
$World =~ s/war/peace/g;
s///
- recherche et remplacement
$text = "The quick quick brown fox jump jump over the lazy dog.";
$text =~ s/(\w+) +\1/$1/;
Regexp::Keep
de Jeff Pinyan sur le CPAN
préserve la partie à gauche de \K
s/(save)delete/$1/
devient s/save\Kdelete//
identique mais bien plus rapide
fonctionne par simple déplacement de pointeur, au lieu de réaliser des sauvegardes et copies de chaînes
split
, join
:
$line = "saper:500:500:Sébastien Aperghis-Tramoni:/home/saper:/bin/bash"; @fields = split /:/, $line; print $fields[5]; # "/bin/bash"
$fields[3] = "Groucho Marx"; $line = join ":", @fields; print $line; # "saper:500:500:Groucho Marx:/home/saper:/bin/bash"
@flags = qw( UP BROADCAST SMART RUNNING SIMPLEX MULTICAST ); print join ", ", @flags; # "UP, BROADCAST, SMART, RUNNING, SIMPLEX, MULTICAST"
Mastering Regular Expression
par Jeffrey E.F. Friedl
ouvrage de référence en matière d'expressions régulières
toute
Introduction à la programmation en Perl - 4. Expressions régulières
par Sylvain Lhullier
expressions régulières
Perl moderne
expressions régulières actuelles
objet moderne avec Moose
bases de données avec DBI
programmation événementielle avec POE
navigation sur le web avec LWP et WWW::Mechanize