I. Introduction aux expressions régulières▲
Théorie
- Théorie des automates et langages formels.
-
Grammaires de recherche de correspondances :
- DFA : Deterministic Finite Automaton ;
- NFA : Nondeterministic Finite Automaton.
- Principale différence : la gestion du retour en arrière (backtracking).
Historique
- UNIX : qed, ed, grep (BRE, puis ERE).
- POSIX regex (BRE, ERE).
- Perl 5, PCRE, Onigurama, (RE2 (DFA amélioré)).
- Perl 6.
Fonctionnement
- 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
Fonctionnement
- Correspondance de caractères.
-
Motif composé de :
- caractères normaux ;
- métacaractè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}
;
Fonctionnement
- Correspondance de caractères.
-
Motif composé de :
- caractères normaux ;
- métacaractères : {}[]()^$.|*+?\ ;
- séquences d'échappement.
"1000
\t
2000"
=~
/00
\t
20/
; # correspond
"cat"
=~
/
\1
43
\x
61
\x
74/
;# correspond aussi (même si c'est bizarre)
Classes de caractères
- Ensemble de caractères possibles 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
Classes de caractères
- Ensemble de caractères possibles 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"...
Classes de caractères
- 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 de caractères
-
Classes prédéfinies :
- . : tous caractères sauf \n ;
- \d : chiffre décimal ;
- \w : caractère de mot (alphanumérique plus _) ;
- \s : espace normale, tabulation, saut de ligne ;
- \h : espace horizontale ;
- \v : espace verticale ;
-
\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 une espace usuelle ;
- \H : ce qui n'est pas une espace horizontale ;
- \V : ce qui n'est pas une espace verticale.
Classes de caractères
- Exemples :
/
\d\d
:
\d\d
:
\d\d
/
; # format d'heure hh:mm:ss
/[-+]
\d
/
; # correspond à +2, -3, etc.
/end
\.
/
;# correspond à "end."
/end[.]/
; # pareil
Ancres
- Pour ancrer la recherche dans certains points.
- ^ : en début de chaîne.
"beausoleil"
=~
/^soleil/
; # ne correspond pas
Ancres
- Pour ancrer la recherche dans certains points.
- ^ : en début de chaîne.
- $ : en fin de chaîne.
"beausoleil"
=~
/beau$/
;# ne correspond pas
"beausoleil"
=~
/soleil$/
; # correspond
"beausoleil
\n
"
=~
/soleil$/
;# correspond aussi
Ancres
- Pour ancrer la recherche dans certains points.
- ^ : en début de chaîne.
- $ : en fin de chaîne.
- \b : frontière de mot, intervient entre \w et \W.
"beausoleil"
=~
/
\b
beau/
; # correspond
"beausoleil"
=~
/
\b
beau
\b
/
; # ne correspond pas
"beausoleil"
=~
/
\b
soleil/
; # ne correspond pas
Quantifieurs
-
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/
; # /a++/ ne correspond pas
- Résumé :
"Lorem ipsum dolor sit amet"
recherche avide : <<--| <<--| <<--| <<<<<--|
recherche non avide : |--->>> |---> |--->> |--->
recherche possessive : |---| |---| |---| |------|
Groupes
- Pour grouper des sous-motifs : (…).
- Par défaut, groupes capturant.
- Référencés par \1, \2… dans le motif.
- Référencés par $1, $2… en dehors 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é
Alternatives
- Disjonction de sous-motifs au sein d'un groupe.
- Exemple :
/^(add|del|list) +(addr|route|rule|table) .../
# "add addr ..."
# "del rule ..."
# "list route ..."
Captures et alternatives
- 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
Captures numérotées
- 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
;
Captures nommées
- (?<name>pattern) pour nommer une capture.
- \k<name>, \k{name} ou \g{name} pour s'y référer.
- Exemple :
my $find_dup
=
qr/ (?<dup_word>\w+) \s+ \k<dup_word> /
x
;
Captures nommées
- 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.
Non abordés
- Modificateurs : /i, /m,/s, /x, /p, /r, /g, /c, /a, /d, /l, /u.
- Assertion keep, \K.
- Assertion \G.
- Assertions de longueur nulle, de recherche alentour positive ou négative : (?=..), (!..), (?<=..)>, (?<!..).
Non abordés
- Ensembles de classes (?[...]).
- Évaluation de code à la volée : (?{ code }), (??{ code }).
- Verbes de contrôle : (*PRUNE), (*SKIP), (*THEN), (*COMMIT), (*FAIL), (*ACCEPT).
- Unicode.
Motifs récursifs
- Possibles en Perl 5.8, mais de manière horrible.
- Syntaxe mise au propre dans PCRE.
- Principe : réinvocation d'un groupe capturant avec (?PARNO).
- PARNO == numéro de parenthèse (groupe capturant).
- Si précédé d'un signe, compris de manière relative.
Motifs récursifs
- (?2) => le 2e groupe déclaré.
- (?-1) => dernier groupe déclaré.
- (?+1) => prochain groupe qui sera déclaré.
- (?0) ou (?R) pour invoquer à nouveau le motif complet.
- (?&name) => invoque un groupe nommé.
Motifs récursifs
- Reconnaissance de parenthèses imbriquées :
$s
=
"( crack ( kapow ) ( klang ) ouch )"
;
$re
=
qr{ ( # groupe #1
\( # parenthèse ouvrante
(?:
(?> [^()]+ ) # groupe sans retour arrière
|
(?1) # groupe avec parenthèses
)*
\) # parenthèse fermante
)
}
x
;
Motifs récursifs
-
(?(condition)yes-pattern|no-pattern) => construction conditionnelle, accepte :
- un numéro de groupe (1), (2)…
- un nom de groupe <name>,
- un bout de code Perl (?{ CODE }),
- (R) pour vérifier si évaluée au sein d'une récursion,
- avec numéro ((R1), (R2)..) ou nom ((R&name)) d'un groupe pour vérifier si évaluée pendant l'exécution du groupe.
Motifs récursifs
- Cas particulier : (DEFINE).
- Seule la partie yes-pattern est autorisée.
- N'est pas directement exécutée.
- Mais peut entrer dedans en récursion.
- Permet donc de définir des fonctions de regexps.
Motifs récursifs
my $log
=
"192.168.1.11 -> 192.168.1.12 connect tcp 80"
;
$log
=~
m{
(?
<src_addr>
(?&
ip_addr)) # adresse IP source
\s+
->
\s+
(?
<dest_addr>
(?&
ip_addr)) # adresse IP destination
(?
(DEFINE)
(?
<ip_addr>
...) # motif pour reconnaître une
) # addresse IP
}x
En ligne
- IRC : Freenode, #regex.
-
Bibliographie
-
Perl moderne par Sébastien Aperghis-Tramoni, Philippe Bruhat, Damien Krotkine, Jérôme Quelin.
- Mastering Regular Expressions, par Jeffrey E.F. Friedl.