Sommaire
Expressions régulières compatibles Perl
preg_match
preg_match_all
preg_replace
preg_replace_callback
preg_split
preg_quote
preg_grep
options de recherche
syntaxe des masques
|
6.85.9 syntaxe des masques[ Exemples avec syntaxe des masques ] Description
La bibliothèque PCRE est un ensemble de fonctions qui
implémentent la recherche par expressions
régulières, en utilisant la même syntaxe
et la même sémantique que le Perl 5, avec quelques
nuances (voir ci-dessous). L'implémentation actuelle
est celle de Perl 5.005.
Différences avec Perl
Les différences avec le Perl 5.005 sont présentée ici :
Par défaut, un caractère d'espacement correspond à
n'importe quel caractère que la fonction C isspace() reconnaît,
bien qu'il soit possible de recompiler la bibliothèque PCRE avec
d'autres tables de caractères. Normalement, isspace() retourne
TRUE pour les espaces, les retours chariot, les
nouvelles lignes, les formfeed, les tabulations verticales et horizontales.
Le Perl 5 n'accepte plus la tabulation verticale comme caractère
d'espacement. La séquence \v qui était dans la documentation
Perl depuis longtemps n'a jamais été reconnue. Cependant, la
tabulation verticale elle-même était reconnue comme un
caractère d'espacement jusqu'à la version 5.002. Avec les
version 5.004 et 5.005, l'option \s l'ignore.
PRCE ne tolère pas la répétition de quantificateurs
dans les expressions. Perl le permet, mais cela ne signifie pas ce que vous
pourriez penser. Par exemple, (?!a){3} ne s'interprète pas : les trois
caractères suivants ne sont pas des "a". En fait, cela
s'interprète comme : le caractère suivant n'est pas "a" trois fois.
Les occurrences de sous-masques qui interviennent dans des assertions
négatives sont comptées, mais elles ne sont pas
enregistrées dans le vecteur d'occurrences. Perl modifie ses
variables numériques pour toutes les occurrences de sous-masque,
avant que l'assertion ne vérifie le masque entier, et uniquement si
les sous-masques ne trouvent qu'une seule occurrence.
Bien que les caractères nul soient tolérés dans la
chaîne de recherche, ils ne sont pas acceptés dans le
masque, car le masque est utilisé comme une chaîne C
standard, terminée par le caractère nul. Il faut donc
utiliser la séquence d'échappement "\0" dans le masque
pour rechercher les caractères nul.
Les séquence d'échappement suivantes ne sont pas
supportées par le Perl: \l, \u, \L, \U, \E,
\Q. En fait, elles sont implémentées par la gestion
intrinsèque de chaînes du Perl, et ne font pas partie
de ses caractères spéciaux.
L'assertion \G du Perl n'est pas supportée car elle n'est pas
pertinente pour faire des recherches avec des masques uniques.
De manière assez évidente, PCRE n'accepte pas la
construction (?{code}).
Au moment de l'écriture de PCRE, Perl 5.005_02 avait quelques
comportements étranges avec la capture des chaînes
lorsqu'une partie du masque est redoublée. Par exemple, "aba" avec
le masque /^(a(b)?)+$/ va affecter à $2 la valeur "b", mais la
même manipulation avec "aabbaa" et /^(aa(bb)?)+$/ laissera $2 vide.
Cependant, si le masque est remplacé par /^(aa(b(b))?)+$/ alors $2
(et d'ailleurs $3) seront correctement affectés. Avec le Perl
5.004, $2 sera correctement affecté dans les deux cas, et c'est
aussi vrai avec PCRE. Si Perl évolue vers un autre comportement
cohérent, PCRE s'adaptera probablement.
Une autre différence encore non résolue est le fait qu'en
Perl 5.005_02 le masque /^(a)?(?(1)a|b)+$/ accepte la chaîne "a",
tandis que PCRE ne l'accepte pas. Cependant, que ce soit avec Perl ou
PCRE /^(a)?a/ et "a" laisseront $1 vide.
PCRE propose quelques extensions aux expressions régulières du Perl.
(a) Bien que les assertions avec retour (lookbehind) soit obligée
d'apparier une chaîne de longueur fixe, toutes les assertions avec
retour peuvent avoir une longueur différente. Perl 5.005 leur
impose d'avoir toutes la même longueur.
(b) Si PCRE_DOLLAR_ENDONLY est
activé, et que PCRE_MULTILINE
n'est pas activé, le méta caractère
$ ne s'applique qu'à la fin
physique de la chaîne, et non pas avant les caractères
de nouvelle ligne.
(c) Si PCRE_EXTRA est
activé, un antislash suivi d'une lettre sans signification
spéciale est considérée comme une erreur.
(d) SI PCRE_UNGREEDY est
activé, la "gourmandise" des quantificateurs de
répétition est inversées, ce qui est rend non
gourmand par défaut, mais s'ils sont suivis de ?, il seront
gourmands.
-
-
Détails sur les expressions régulières
Introduction
La syntaxe et la sémantique des expressions régulière
supportées par PCRE sont décrites ci-dessous. Les expressions
régulières sont aussi décrites dans la documentation
Perl, et dans un grand nombre d'autres livres, avec de nombreux exemples.
Jeffrey Friedl's "Mastering Regular Expressions", édité
chez O'Reilly (ISBN 1-56592-257-3), les décrits en profondeur.
Cette description est organisée comme une documentation de
référence.
Une expression régulière est un masque, appliqué à
une chaîne sujet, de gauche à droite. La plupart des
caractères se représentent eux-mêmes. Un exemple
trivial : un masque qui serait "Le rapide renard gris",
pourra correspondre à une partie de la chaîne sujet qui sera
identique au masque, comme par exemple
"Le rapide renard gris court dans la forêt",
Méta-caractères
La puissance des expressions régulières provient de
leur capacité à autoriser des alternatives et des quantificateurs
de répétition dans le masque. Ils sont encodés
dans le masque par des méta-caractères, qui ne représentent
pas ce qu'ils sont, mais sont interprétés d'une certaine
manière.
Il y a deux sortes de méta-caractères : ceux qui sont
reconnus n'importe où dans un masque, hormis entre crochets,
et ceux qui sont reconnus entre crochets.
A l'extérieur des crochets, les méta caractères sont :
- /
Caractère d'échappement, avec de multiples usages
- ^
Le début de la chaîne sujet (ou de ligne, en mode multiligne)
- $
La fin de la chaîne sujet (ou de ligne, en mode multiligne)
- .
Remplace n'importe quel caractère, hormis le caractère
de nouvelle ligne (par défaut) ;
- [
Caractère de début de définition de classe
- ]
Caractère de fin de définition de classe
- |
Caractère de début d'alternative
- (
Caractère de début de sous-masque
- )
Caractère de fin de sous-masque
- ?
Etend le sens de (; quantificateur de 0 ou 1; quantificateur de minimisation
- *
Quantificateur de 0 ou plus
- +
Quantificateur de 1 ou plus
- {
Caractère de début de quantificateur minimum/maximum
- }
Caractère de fin de quantificateur minimum/maximum
La partie du masque qui est entourée de crochet et appelé
une classe de caractères. Dans les classes de caractères,
les seuls méta caractères autorisés sont :
- \
Caractère d'échappement, avec de multiples usages
- ^
Négation de la classe, mais uniquement si placé tout
au début de la classe
- -
Indique un intervalle de caractères
- ]
Termine la classe de caractères
La section suivante décrit l'utilisation de chaque
méta-caractères.
Antislash
Le caractère antislash a de nombreuses utilisations.
En premier lieu, s'il est suivi d'un caractère non
alpha-numérique, il ne prendra pas la signification
spéciale qui y est rattachée. Cette utilisation de
l'antislash comme caractère d'échappement s'applique
à l'intérieur et à l'extérieur des
classes de caractères. Par exemple, pour recherche le
caractère étoile "*", il faut
écrire dans le masque : "\*". Cela
s'applique dans tous les cas, que le caractère qui suive
soit un méta-caractère ou non. C'est un moyen sûr
pour s'assurer qu'un caractère sera recherché
pour sa valeur littérale, plutôt que pour sa valeur
spéciale. En particulier, pour rechercher les antislash,
il faut écrire : "\\".
Si un masque est utilisé avec l'option
PCRE_EXTENDED,
les espaces blancs du masque, mais qui ne sont pas dans une
classe de caractères, et les caractères entre dièses
"#", ainsi que les nouvelles lignes sont ignorées.
L'antislash peut être utilisé pour échapper et ainsi
rechercher un espace ou un dièse.
La deuxième utilité de l'antislash est de pouvoir
coder des caractères invisibles dans les masques. Il n'y
a pas de restriction sur la place de ces caractères
invisibles, hormis pour le caractère nul qui doit terminer
le masque.
Lors de la préparation du masque, il est souvent plus pratique
d'utiliser les séquences d'échappement suivantes,
plutôt que le caractère binaire qu'elle représente :
- \a
alarme, c'est-à-dire le caractère BEL (hex 07)
- \cx
"control-x", avec x qui peut être n'importe quel
caractère.
- \e
escape (hex 1B)
- \f
formfeed (hex 0C)
- \n
nouvelle ligne (hex 0A)
- \r
retour chariot (hex 0D)
- \t
tabulation (hex 09)
- \xhh
caractère en hexadécimal, de code hh
- \ddd
caractère en octal, de code ddd, ou référence
arrière
Dans la séquence "\cx" si "x"
est en minuscule, il est converti en majuscule. Puis, le bit 6 (hex 40)
est inversé. Ainsi "\cz" devient 1A,
mais "\c{" devient hex 3B, tandis que "\c;"
devient hex 7B.
Après "\x", deux caractères
hexadécimaeux sont lus (les lettres peuvent être en majuscule
ou minuscule).
Après "\0", deux caractères octal sont lus.
Dans chacun des cas, le méta-caractère tente de lire autant
de caractère que possible. Ainsi la séquence
"\0\x\07", sera comprise comme deux caractères nuls,
suivi d'un caractère alarme (BEL). Assurez-vous que vous fournissez
suffisamment de chiffres après le méta-caractère.
La gestion de la séquence "\y", avec y <> 0
est plutôt compliquée. En dehors des caractères de classes,
PCRE va lire y et tous les caractères qui suivent comme des chiffres
décimaux. Si y est plus petit que 10, ou bien s'il y a
déjà eu au moins autant de parenthèses ouvrantes
auparavant, la séquence est prise pour une référence
arrière. Le détail sera vu ultérieurement, après la
section sur les sous-masques.
A l'intérieur d'un caractère de classe, ou si y est plus
grand que 10, et qu'il n'y a pas eu assez de parenthèses ouvrantes
auparavant, PCRE lis jusqu'à 3 chiffres octals à la suite
de l'antislash, et génère un octet unique, à partir
des 8 bits de poids faible de la séquence. Tous les chiffres qui
suivent ne sont pas interprétés, et se representent
eux-mêmes. Par exemple:
- \040
une autre manière d'écrire un espace
- \40
identique, dans la mesure où il n'y a pas 40
parenthèses ouvrantes auparavant
- \7
est toujours une référence arrière
- \11
peut être une référence de retour,
ou une tabulation
- \011
toujours une tabulation
- \0113
est une tabulation suivi du caractère "3"
- \113
est le caractère 113 (étant donné qu'il ne
peut y avoir plus de 99 références arrières)
- \377
est un octet dont tous les bits sont à 1
- \0113
peut être soit une référence arrière,
soit le caractère NULL, suivi des caractères "8" et "1"
Les valeurs octales supérieures ou égales à 100 ne
doivent pas être introduites par un 0, car seuls les trois premiers
octets seront lus.
Toutes les séquences qui définissent une valeur d'un seul
octet peuvent être utilisé dans les classes de caractères,
et à l'extérieur. De plus, dans une classe de caractères,
la séquence "\b" est interprétée
comme un caractère effacer (backspace, hex 08). A l'extérieur
d'une classe de caractères, il peut avoir d'autres significations
(voir ci-dessous).
On peut encore se servir de l'antislash pour préciser des types
génériques de valeurs :
- \d
tout caractère décimal
- \D
tout caractère qui n'est pas un caractère décimal
- \s
tout caractère blanc
- \S
tout caractère qui n'est pas un caractère blanc
- \W
tout caractère de "mot"
- \w
tout caractère qui n'est pas un caractère de "mot"
Chaque paire précédente définit une partition de
la table des caractères : les deux ensembles sont disjoints.
Un caractère satisfera soit un méta-caractère,
soit l'autre.
Un caractère de "mot" sera une lettre, un chiffre ou le
caractère souligné, c'est-à-dire un
caractère qui pourra être une partie d'un mot Perl. La
définition des lettres et chiffres est définie par les
tables de caractères de PCRE, et peut varier suivant la table
locale de caractère (voir "Tables de caractères locales ",
ci-dessus. Par exemple, dans la configuration français ("fr"),
certains caractères ont des codes supérieurs à
128, pour les caractères accentués, et ils seront compris
par le méta caractère \w.
Ces séquences de caractères peuvent apparaître à
l'intérieur ou à l'extérieur des classes de
caractères. Elles remplacent à chaque fois un
caractère du type correspondant. Si cette séquence est
placée en fin de masque, et qu'il n'y a plus de caractère à
comparer dans la chaîne sujet, la recherche échoue.
La quatrième utilisation de l'antislash intervient lors d'assertions
simples. Une assertion impose une condition à un certain point,
sans remplacer de caractère. L'utilisation de sous-masques pour
réaliser des assertions plus complexes est décrites
plus-bas. Les assertions avec antislash sont les suivantes :
- \b
limite de mot
- \B
pas limite de mot
- \A
début de la chaîne sujet
(indépendant du mode multi-lignes)
- \Z
fin de la chaîne sujet ou nouvelle ligne à
la fin de la chaîne sujet
(indépendant du mode multi-lignes)
- \z
fin de la chaîne sujet
(indépendant du mode multi-lignes)
Ces assertions ne peuvent pas apparaître dans une classe de
caractères (mais "\b" a une autre signification à
l'intérieur d'une classe de caractères).
Une limite de mot est un emplacement dans la chaîne sujet ou un
caractère et son suivant ne sont pas en même temps des
caractères de mot, ou le contraire (on peut le voir comme
\w\W ou \W\w), ou encore le
premier ou le dernier caractère est un caractère mot.
Les assertions \A, \Z, et
\z diffèrent des méta caractères
^ et $ dans la mesure où
ils ne sont pas dépendants des options, notamment
PCRE_NOTBOL
ou PCRE_NOTEOL.
La différence entre \Z et
\z tient au fait que \Z recherche
les positions avant les nouvelles lignes et à la fin de la
chaîne sujet, tandis que \z ne recherche
que la fin de la chaîne.
Accent circonflexe et Dollar
En dehors d'une classe de caractères, avec les options par
défaut, ^ est une assertion qui n'est
vraie que si elle est placée tout au début de la
chaîne. A l'intérieur d'une classe de caractères,
^ a un tout autre sens (voir ci-dessous).
^ n'a pas besoin d'être le premier
caractère du masque, si plusieurs alternatives sont
proposées, mais il doit être placé en
premier dans chaque alternative. Si toutes les alternatives
commencent par ^, alors le masque est dit ancré
(il y a une autre construction qui porte cette appellation).
$ est une assertion qui n'est vraie que si elle
est placée tout en fin de chaîne ou juste avant un
caractère de nouvelle ligne qui serait le dernier
caractère de la chaîne. A l'intérieur d'une
classe de caractères, $ a un tout autre
sens (voir ci-dessous).
$ n'a pas besoin d'être le dernier
caractère du masque, si plusieurs alternatives sont
proposées, mais il doit être placé en dernier
dans chaque alternative. Si toutes les alternatives finissent par
$, alors le masque est dit ancré (il y
a une autre construction qui porte cette appellation). $
n'a pas de valeur particulière dans une classe de
caractères.
La signification de $ peut changer, de manière
à l'amener à ce qu'il ne puisse se trouver qu'en toute
fin de la chaîne sujet. Cela se fait en ajoutant l'option
PCRE_DOLLAR_ENDONLY
au moment de la compilation, ou de l'exécution.
Cette option est inopérante sur \Z.
La signification de ^ peut changer, de manière
à l'amener à ce qu'il puisse se trouver immédiatement
avant et immédiatement après un caractère de nouvelle
ligne "\n". Cela se fait en ajoutant l'option
PCRE_MULTILINE au moment de
la compilation ou de l'exécution.
Par exemple, le masque /^abc$/ accepte la chaîne
"def\nabc" uniquement en mode multi-lignes. Par
conséquent, toutes les parties du masques qui commencent par
"^" ne sont pas ancrées, en mode multi-lignes.
L'option PCRE_DOLLAR_ENDONLY
est ignorée si l'option
PCRE_MULTILINE est choisie.
Notez que les méta caractères \A,
\Z, et \z peuvent servir à
répérer le début et la fin du sujet, et toutes les
parties du masque qui commenceront par \A seront toujours
ancrées, avec l'option
PCRE_MULTILINE ou non.
Point
En dehors d'une classe de caractères, un point remplace n'importe
quel caractère, même invisible et à l'exception du
caractère de nouvelle ligne. Avec l'option
PCRE_DOTALL le point
remplace n'importe quel caractère, même le caractère de
nouvelle ligne. La gestion des points et complètement
indépendante de ^ et $.
Le seul point commun est que les deux ont un comportement particulier vis
à vis des caractère de nouvelle ligne.
Le point n'a pas de comportement particulier dans une classe de
caractères.
Crochets
Un crochet ouvrant [ introduit une classe de
caractères, et le crochet fermant ]la
conclut. Le crochet fermant n'a pas de signification en lui-même.
Si le crochet fermant est nécessaire à l'intérieur
d'une classe de caractères, il faut qu'il soit le premier
caractère (après un ^ éventuel)
ou échappé avec un antislash.
Une classe de caractères remplace un seul caractère
dans la chaîne sujet, à moins que le premier
caractère de la classe soit un accent circonflexe
^, qui représente une négation :
le caractère ne doit pas se trouver dans la classe. Si
^ est nécessaire dans la classe, il
suffit qu'il ne soit pas le premier caractère, ou bien
qu'il soit échappé avec un antislash.
Par exemple, le caractère [aeiou] remplace
n'importe quelle voyelle minuscule, tandis que [^aeiou]
remplace n'importe quelle caractère qui n'est pas une voyelle
minuscule. ^ est une notation pratique pour
spécifier des caractères qui sont dans une classe,
en ne citant que ceux qui n'y sont pas. Le comportement est inchangé.
Avec l'option d'insensibilité à la casse, toutes les lettres
d'une classe de caractères représentent en même temps
la majuscule et la minuscule. Par exemple, [aeiou]
représentera "A" ou "a", et
[^aeiou] n'acceptera pas ni "A",
tandis que sans l'option, elle l'accepterait.
Le caractère de nouvelle ligne n'est pas traité de
manière spéciale dans les classes de caractères,
quelque soit l'option PCRE_DOTALL
ou PCRE_MULTILINE. Une classe
telle que [^a] acceptera toujours une nouvelle ligne.
Le signe moins (-) est utilisé pour
spécifier un intervalle de caractères, dans
une classe. Par exemple, [d-m] remplace toutes
les lettres entre d et m inclus. Si le caractère moins est
requis dans une classe, il faut l'échapper avec un antislash,
ou le faire apparaître à une position ou il ne pourra
pas être interprété comme une indication d'intervalle,
c'est-à-dire au début ou à la fin de la classe.
Il n'est pas possible d'avoir le caractère crochet fermant
"]" comme fin d'intervalle. Un masque tel que
[W-]46] est compris comme la classe de caractères
contenant deux caractères ("W" et "-") suivi de la chaîne
littérale "46]", ce qui fait qu'il va accepter
"W46]" ou "-46]". Cependant, si
"]" est échappé avec un antislash, le
masque [W-\]46] est interprété comme
une classe d'un seul caractère, contenant un intervalle de
caractères.
La valeur octale ou hexadécimale de "]" peut
aussi être utilisée pour déterminer les limites
de l'intervalle. Les intervalles travaillent sur des
séquences ASCII. Ils peuvent aussi être
précisées avec des valeurs numériques, par exemple
"[\000-\037]".
Si cet intervalle inclut des lettres utilisées avec une
option d'insensibilité de casse, les majuscules ou minuscules
correspondantes seront aussi incluses. Par exemple,
"[C-c]" est équivalent é
"[][\^_`wxyzabc]", avec l'option
d'insensibilité de casse. Si la table locale de
caractères est "fr", "[\xc8-\xcb]"
correspond aux caractères accentués.
Les types de caractères \d,
\D, \S, \s,
\w, \W peuvent aussi intervenir
dans les classes de caractères. Par exemple,
"[][\^_`wxyzabc][\dABCDEF]" acceptera n'importe
quel caractère hexadécimal. Un accent circonflexe peut
aussi être utilisé pour spécifier adroitement
des ensembles de caractères plus restrictifs : par exemple
[^\W_] accepte toutes les lettres et les chiffres,
mais pas les soulignés. Tous les caractères non alpha-
numériques autres que \, -, ^ (placés
en début de chaîne) et ] n'ont pas de
signification particulière, mais ils ne perdront rien à
être échappés.
Barre verticale
La barre verticale | sert à séparer des
alternatives. Par exemple, dans le masque "/dupont|martin/"
recherche soit "dupont", soit "martin".
Le nombre d'alternatives n'est pas limité, et il est même possible
d'utiliser la chaîne vide. Lors de la recherche, toutes les alternatives
sont essayées, de gauche à droite, et la première qui est
acceptée est utilisée.
Si les alternatives sont dans un sous-masque, elle ne réussiront
que si le masque principal réussi aussi.
Options internes
Les options PCRE_CASELESS,
PCRE_MULTILINE,
PCRE_DOTALL et
PCRE_EXTENDED peuvent
être changée à l'intérieur du masque
lui-même, avec des séquences mises entre
"(?" et ")".
Les options sont :
- i
PCRE_CASELESS
- m
PCRE_MULTILINE
- s
PCRE_DOTALL
- x
PCRE_EXTENDED
Par exemple, (?im) rend le masque insensible à
la casse, et multi-lignes. Il est possible d'annuler ces options en les
faisant précéder par un signe - : par
exemple (?im-sx), ajoutera les options
PCRE_CASELESS
et PCRE_MULTILINE mais
annulera les options PCRE_DOTALL
et PCRE_EXTENDED.
Si une option apparaît avant et après le signe moins, l'option
sera annulée.
Le domaine d'application de ces options dépend de la position de
la séquence d'option. Pour toutes les séquences d'options
qui sont hors des sous-masques (définis plus loin), l'effet est le
même que si l'option avait été fixée dès
le début de la recherche. Les exemples suivants se comportent tous
de la même façons : (?i)abc,
a(?i)bc, ab(?i)c,
abc(?i), et sont parfaitement équivalents au
masque abc avec l'option
PCRE_CASELESS. En d'autres
termes, activer des séquences d'options dans le corps principal
du masque revient à appliquer l'option à tout le masque, sauf
ordre contraire dans les sous-masques. S'il y a plusieurs séquences
d'options qui portent sur la même option, la dernière s'appliquera.
Si une option intervient dans un sous-masque, le comportement est différent.
C'est un changement de comportement apparu en Perl 5.005. Une option à
l'intérieur d'un sous-masque n'affecte que cette partie du masque, ce
qui fait que (a(?i)b)c acceptera abc
et aBc mais aucune autre chaîne (en supposant que
PCRE_CASELESS n'est pas
utilisé). Cela signifie que les options permettent d'avoir
différente configuration de recherche pour différentes
parties du masque.
Une séquence d'options dans une alternative affecte toute
l'alternative. Par exemple : (a(?i)b|c) accepte
"ab", "aB", "c",
et "C", même si, comme dans le cas de
"C", la première alternative qui porte
l'option n'est pas prise en compte. Sinon, cela risque d'introduire
des comportements très étranges : les options
spécifiques à PCRE telles que
PCRE_UNGREEDY et
PCRE_EXTRA peuvent
être modifiées de la même
manière, en utilisant respectivement les caractères
U et X. L'option (?X) est particulière,
car elle doit toujours intervenir avant toutes les autres options,
même au niveau du masque entier. Il vaut mieux l'activer au
début du masque.
Sous-masques
Les sous-masques sont délimités par des parenthèses,
et peuvent être imbriquées. Ajouter des sous-masques a deux
utilités :
1. Délimiter des alternatives. Par exemple, le masque
char(don|mant|) acceptera les mots
"char", "charmant", ou
"charmant". Sans les parenthèses, il
n'accepterait que "chardon",
"mant" ou la chaîne vide "".
2. Le sous-masque est considéré comme capturant : lorsqu'une
chaîne sujet est acceptée par le masque complet, les
sous-masques sont transmis à l'appelant grâce à
un vecteur de sous-masques. Les parenthèses ouvrantes sont
comptées de gauche à droite, (commençant à 1).
Par exemple, soit la chaîne sujet "le roi soleil"
qui est utilisée avec le masque suivant :
Le ((roi|prince) (soleil|charmant)) les sous-masques
capturé sont "roi soleil", "roi",
et "soleil", numérotés respectivement 1, 2, et 3.
L'ubiquité des parenthèses n'est pas toujours simple
d'emploi. Il y a des moments où regrouper des sous-masques
est nécessaire, sans pour autant capturer la valeur trouvée.
Si une parenthèse ouvrante est suivie de "?:",
le sous-masque ne capture pas la chaîne assortie, et ne sera pas
compté lors de la numérotation des captures. Par exemple,
avec la chaîne "le prince charmant", utilisé
avec le masque Le (( ?roi|prince) (soleil|charmant))
les chaînes capturées seront "prince charmant"
et "charmant", numérotés respectivement 1
et 2.
Le nombre maximal de chaîne capturées est de 99, et le
nombre total de sous-masque (capturant ou non) ne doit pas
dépasser 200.
(?i:samedi|dimanche) et
(?:(?i) samedi | dimanche) : De plus, comme les
séquences d'options sont valables sur toute une alternative,
les masques ci-dessus accepteront aussi bien "DIMANCHE" que "Dimanche".
Répétitions
Les répétitions sont spécifiées avec
des quantificateurs, qui peuvent être placés à
la suite des caractères suivants :
- a
Un caractère unique, même s'il s'agit
d'un méta caractère
- [abc]
Une classe de caractères
- \2
Une référence de retour (Voir section suivante)
- (a|b|c)
Un sous-masque avec parenthèses (à moins que ce ne soit
une assertion, voir plus loin)
Les quantificateurs généraux précisent un nombre
minimum et maximum de répétitions possibles, donnés
par deux nombres entre accolades, et séparés par une virgule.
Ces nombres doivent être plus petits que 65536, et le premier nombre
doit être égal ou inférieur au second. Par exemple
z{2,4} accepte "zz",
"zzz", ou "zzzz". L'accolade fermante
n'a pas de signification par elle-même.
Si le second nombre est omis, mais que la virgule est là, cela
signifie qu'il n'y a pas de limite supérieure. Si le second nombre
et la virgule sont omis, le quantificateur correspond au nombre exact de
répétition attendues. Par exemple :
accepte n'importe quelle succession d'au moins 3 voyelles minuscules, tandis
que \d{d} n'accepte que 8 chiffres exactement.
Une accolade ouvrante qui apparaît à une position où
un quantificateur n'est pas accepté, ou si la syntaxe des
quantificateurs n'est pas respectée, sera considérée
littérale. Par exemple, "{,6}" n'est pas un
quantificateur, mais une chaîne de 4 caractères.
Le quantificateur {0} est autorisé, mais l'expression est alors
ignorée.
- *
équivalent à {0,}
- +
équivalent à {1,}
- ?
équivalent à {0,1}
Il est possible de constituer des boucles infinies en créant un sous-masque
sans caractères, mais pourvu d'un quantificateur sans limite
supérieure. Par exemple "(a?)*.
Les versions plus anciennes de Perl et PCRE généraient alors
une erreur au moment de la compilation. Cependant, étant donné
qu'il existe des situations où ces constructions peuvent être
utiles, ces masques sont désormais autorisés. Cependant, si
la répétion du sous-masque ne trouve aucun caractère,
la boucle est interrompue.
Par défaut, les quantificateurs sont dits "gourmands", c'est à
dire, qu'ils cherchent d'abord à trouve le nombre maximal de
répétitions qui autorise le succès de la recherche.
L'exemple classique posé par cette gourmandise est la recherche de
commentaires d'un programme en C. Les commentaires apparaissent entre les
séquences /*....*/ et à l'intérieur
de ces délimiteurs, les * et /
sont autorisés. Appliquer le masque /\*.*\*/
à la chaîne
/* first commet */ not comment /* second comment */
ne peut réussir, car le masque travaille sur toute la chaîne,
à cause de la gourmandise du caractère .*.
Cependant, un quantificateur suivi d'un point d'interrogation cesse
d'être gourmand, et au contraire, ne recherche que le nombre
minimum de répétition. Dans ces conditions, le masque
/\*.*?\*/ trouvera bien les commentaires du code
C. La signification des autres quantificateurs n'est pas changée.
Attention à ne pas confondre l'utilisation du point d'interrogation
ici avec son utilisation comme quantificateur lui-même.
A cause cette ambiguité, il peut apparaître des situations
où il faut le doubler : \d??\d. Ce masque va
tenter de lire un seul chiffre, mais le cas échéant,
il acceptera 2 chiffres pour permettre à la recherche
d'aboutir. Si l'option PCRE_UNGREEDY
est activée, (une option qui
n'est pas disponible avec Perl) alors les quantificateurs sont
non gourmand par défaut, mais peuvent être
rendu gourmand au cas par cas, en ajoutant un point d'interrogation
après. En d'autres termes, cette option inverse le comportement par
défaut.
Lorsqu'un sous-masque est quantifié avec un nombre minimum
de répétitions, qui soit plus grand que 1, ou avec
un maximum de répétitions, le masque compilé aura
besoin de plus de place de stockage, proportionnellement au minimum
et au maximum.
Si un masque commence par ..* ou .{0,}
et que l'option PCRE_DOTALL
(équivalent en Perl à /s) est
activée, c'est-à-dire en autorisant le remplacement des nouvelles
lignes par un méta-caractère, alors le masque est
implicitement ancré, car tout ce qui suit va être
mangé par la première séquence, et se comportera
comme si le masque se terminait par le méta caractère
\A. Dans le cas où on sait d'avance qu'il
n'y aura pas de caractère de nouvelle ligne, activer l'option
PCRE_DOTALL et commencer
le masque par .* permet d'optmiser le masque.
Alternativement, on peut utiliser ^ pour ancrer
explicitement le masque. Lorsqu'un sous-masque capturant est
répété, la valeur capturée est la
dernière. Par exemple, après que
"(inter[net]{3}\s*)+" ai été
appliqué à "internet interne",
la valeur de la chaîne capturée est "interne".
Cependant, s'il y a des sous-masques imbriqués, la valeur
capturée correspondante peut l'avoir été lors
des précédentes itérations. Par exemple :
/(a|(b))+/ accepte "aba" et
la deuxième valeur capturée est "b".
Références arrières
En dehors des classes de caractères, un antislash suivi
d'un nombre plus grand que 0 (et possiblement plusieurs chiffres)
est une référence arrière (c'est à
dire vers la gauche) dans le masque, en supposant qu'il y ait
suffisamment de sous-masques capturants précédants.
Cependant, si le nombre décimal suivant l'antislash est
plus petit que 10, il sera toujours considéré
comme une référence arrière, et cela
génèrera une erreur si le nombre de capture
n'est pas suffisant. En d'autres termes, il faut qu'il existe
suffisamment de parenthèses ouvrantes à gauche
de la référence, surtout si la référence
est inférieure à 10.
Reportez-vous à la section "antislash" pour avoir de
plus amples détails à propos du nombre de
chiffres qui suivent l'antislash.
La référence arrière remplace ce qui a
été capturé par un sous-masque dans le
masque courant, plutôt que remplace le sous-masque
lui-même. Ainsi (calme|rapide) et
\1ment trouvera "calme et calmement"
et "rapide et rapidement", mais pas
"calme et rapidement". Si la recherche tient
compte de la casse, alors la casse de la chaîne
capturée sera importante. Par exemple,
((?i)rah)\s+\1 trouve "rah rah"
et "RAH RAH", mais pas "RAH rah",
même si le sous-masque capturant initial ne tenait pas compte
de la casse.
Il peut y avoir plusieurs références arrières dans
le même sous-masque. Si un sous-masque n'a pas été
utilisé dans une recherche, alors les références
arrières échoueront. Par exemple "(a|(bc))\2"
ne réussira jamais si la chaîne sujet commence par
"a" plutôt que par "bc".
Etant donné qu'il peyt y avoir jusqu'à 99 références
arrières, tous les chiffres après l'antislash sont
considérés comment faisant potentiellement partie de
la référence arrière. Si le masque recherche un
chiffre après la référence, alors il faut
impérativement utiliser des délimiteurs pour terminer
la référence arrière.
>
Si l'option PCRE_EXTENDED
est activée, on peut utiliser un espace.
Sinon, un commentaire vide fait l'affaire. Une référence
arrière qui intervient à l'intérieur de
parenthèses auquel elle fait référence
échouera dès que le sous-masque sera utilisé. Par exemple,
(a\1) échouera toujours. Cependant, ces
références peuvent être utiles dans les
sous-masques répétitifs. Par exemple, le masque
"(a|b\1)+" pourra convenir pour "a",
"aba", "ababaa", etc....
A chaque itération du sous-masque, la référence
arrière utilise le résultat du dernier sous-masque.
Pour que cela fonctionne, il faut que la première
itération n'ai pas besoin d'utiliser la référence
arrière. Cela arrive avec les alternatives, comme dans
l'exemple ci-dessus, ou avec un quantificateur de minimum 0.
Assertions
Une assertion est un test sur les caractères suivants ou
précédent celui qui est en cours d'étude. Ce
test ne consomme par de caractère (ie, on ne déplace
pas le pointeur de caractères). Les assertions simples sont
codées avec \b, \B,
\A, \Z, \z,
^ et $, et sont décrites
précédemment.
Il existe cependant un type d'assertions plus complexes, codées
sous la forme de sous-masques. Il en existe deux types : celles qui
travaillent au-delà de la position courante (\w+(?=;)),
et celles qui travaillent en deça ((?!)\w+).
Une assertion se comporte comme un sous-masque, hormis le fait qu'elle
ne déplace pas le pointeur de position. Les assertions avant
commencent par (?= pour les assertions positives, et
par (?!, pour les assertions négatives. Par exemple :
\w+(?=;) s'assure qu'un mot est suivi d'un point-virgule,
mais n'inclus pas le point virgule dans la capture. D'autre part,
(?!foo)bar en est proche, mais ne trouve pas une
occurrence de "bar" qui soit précédée
par quelque chose d'autre que "foofoo"; il trouve toutes
les occurrences de "bar", quelque soit ce qui
le précéde, car l'assertion (?!foo)
est toujours vraie quand les trois caractères suivants sont
"bar". Une assertion arrière est ici
nécessaire.
Les assertions arrières commencent par (?<=
pour les assertions positives, et (?<! pour les
assertions négatives. Par exemple : (?<!foo)bar
trouve les occurrences de "bar" qui ne sont pas
précédées par "foo".
Le contenu d'une référence arrière est limité
de telle façon que les chaînes qu'il utilise
soient toujours de la même taille. Cependant, lorsqu'il
y a plusieurs alternatives, elles n'ont pas besoin d'être
de la même taille. Par exemple, (?<=bullock|donkey)
est autorisé, tandis que (?<!dogs?|cats?)
provoque une erreur de compilation. Les alternatives qui ont des
longueurs différentes ne sont autorisées qu'au niveau
supérieur des assertions arrières. C'est une
amélioration du fonctionnement de Perl 5.005, qui impose
aux alternatives d'avoir toutes la même taille. Une
assertion telle que (?<=ab(c|de)) n'est pas
autorisée, car l'assertion de bas niveau (la deuxième,
ici) a deux alternatives de longueurs différentes. Pour
la rendre acceptable, il faut écrire (?<=abc|abde)
L'implémentation des assertions arrières déplace
temporairement le pointeur de position vers l'arrière, et cherche
à vérifier l'assertion. Si le nombre de caractères
est différent, la position ne sera pas correcte, et l'assertion
échouera. La combinaison d'assertions arrières avec des
sous-masques peut être particulièrement pratique à
fin des chaînes. Un exemple est donné à la fin de
cette section.
Plusieurs assertions peuvent intervenir successivement. Par exemple,
le masque (?<=\d{3})(?<!999)foo recherche
les chaînes "foo" précédées
par trois chiffres qui ne sont pas "999". Notez que chaque assertion
est appliquées indépendemment, au même point de
la chaîne à traiter. Tout d'abord, il est
vérifié que les trois premiers caractères ont
tous des chiffres, puis on s'assure que ces trois caractères
ne sont pas "999". Le masque précédant
n'accepte pas "foo" précédé de
6 caractères, les trois premiers étant des chiffres et
les trois suivants étant différents de "999".
Par exemple, ce masque n'acceptera pas la chaîne
"123abcfoo". Pour ce faire, il faut utiliser le masque
suivant : (?<=\d{3}...)(?<!999)foo. Dans ce
masque, la première assertion vérifie les six premiers
caractères, s'assure que les trois premiers sont des entiers,
et la deuxième assertion s'assure que les trois derniers
caractères ne sont pas "999".
De plus, les assertions peuvent être imbriquées :
(?<=(?<!foo)bar)baz recherche les
occurrences de "baz" qui sont
précédées par "bar", qui,
à son tour, n'est pas précédé par
"foo". Au contraire,
(?<=\d{3}(?!999)...)foo est un autre masque,
qui recherche les caractères "foo",
précédés par trois chiffres, suivis trois
autres caractères qui ne forment pas "999".
Les assertions ne sont pas capturantes, et ne peuvent pas être
répétées. Si une assertion contient des sous-masques
capturants en son sein, ils seront compris dans le nombre de sous-masques
capturants du masque entier. La capture est réalisée pour
les assertions positives, mais cela n'a pas de sens pour les
assertions négatives.
200 assertions au maximum sont autorisées.
Sous-masques uniques
Avec les quantificateurs de répétitions, l'échec
d'une recherche conduit normalement à une autre recherche, avec
un nombre différent de répétitions, pour
voir si le masque ne s'applique pas dans d'autres conditions.
Parfois, il est pratique d'éviter ce comportement, soit
pour changer la nature de la recherche, soit pour la faire abandonner
plus tôt, si on pense qu'il n'est pas besoin d'aller plus loin.
Considérons par exemple, le masque \d+foo
appliqué à la ligne 123456bar.
Après avoir tenté d'utiliser les 6 chiffres suivi
de "foo" qui font échouer, l'action habituelle
sera de réessayer avec 5 chiffres, puis avec 4, et ainsi de
suite jusqu'à l'échec final.
Un sous-masque évalué une seule fois permettrait
d'indiquer que lorsqu'une partie du masque est trouvée, elle
n'a pas besoin d'être réévaluée à
chaque tentative. Ceci conduirait à ce que la recherche
échoue immédiatement après le premier test.
Ces assertions ont leur propre notation, commençant avec
(?> comme ceci : (?>\d+)bar.
Ce type de parenthèses verrouille le sous-masque qu'il contient
un fois qu'il a été trouvé, et empêche un
échec ultérieur d'y repasser, mais autorise à
revenir plus loin en arrière. Une autre description est que
les sous-masques de ce type recherche les chaînes de
caractères, et les ancre le sous-masque à l'intérieur
de la chaîne.
Les sous-masques uniques ne sont pas capturants. Des cas simples comme
ceux présentés ci-dessus peuvent être pris comme
des situations maximisantes, qui réservent le maximum de
caractères. En effet, alors que \d+ et
\d+? ajustent le nombre de chiffres trouvés
de manière à laisser la possibilité au masque de
réussir, (?>\d+) ne peut retenir que la
séquence entière de chiffres. Cette construction peut
contenir un nombre arbitraire de sous-masques complexes, et ils peuvent
être imbriqués.
Les sous-masques uniques ne peuvent être utilisés qu'avec
les assertions arrières, pour effectuer une recherche efficace
en fin de chaîne. Considérons un masque simple tel que
"abcd$" appliqué à une très
longue chaîne qui ne lui correspond pas. A cause du système
de recherche de gauche à droite, PCRE va commencer par rechercher
un "a" dans la chaîne sujet, puis vérifier
si ce qui suit convient au reste du masque. Si le masque est
spécifié sous la forme ^.*abcd$
alors, la séquence .* remplace en premier
lieu la chaîne entière, et échoue, repart en
arrière, et remplace tous les caractères sauf le dernier,
échoue, retourne en arrière, prend un caractère
de moins, etc... et ainsi de suite. Encore une fois, la recherche du
"a" passe en revue toute la chaîne de gauche
à droite, ce qui n'est pas très efficace. Par contre,
si le masque était écrit ^(?>.*)(?<=abcd)
alors il n'y aurait pas de retour en arrière, pour satisfaire
la séquence .*, car elle ne peut que remplacer
toute la chaîne. L'assertion arrière consécutive
va alors faire un test sur les 4 derniers caractères. Si elle
échoue, la recherche est immédiatement interrompue.
Pour les chaînes très longues, cette approche fait la
différence en terme de performances et de temps de recherche.
Lorsqu'un masque contient une répétition illimitée
dans un sous-masque, qui contient lui-même un nombre
illimité de répétiteur, l'utilisation des
sous-masques à utilisation unique sont la seule façon
d'éviter l'échec de la recherche à après un
temps de calcul trop long.
Le masque (\D+|<\d+>)*[!?] recherche un nombre
illimité de sous-chaînes, qui contiennent soit
des non-chiffres, soit des chiffres inclus dans <>, suivi soit
par ! ou par ?. Lorsqu'il trouve
une solution, ce masque va très vite. Mais, lorsqu'il est
appliqué à une chaîne telle que :
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
il lui faut beaucoup de temps pour annoncer un échec. Cela est
dû au fait que la chaine peut être divisée en deux
sous-chaînes d'un grand nombre de façons, et qu'elles
ont toutes été essayées. (Cet exemple utilisait
[!?] plutôt qu'un caractère simple, car
PCRE et PHP utilise une optimisation qui leur permettent de détecter
rapidement l'échec lorsqu'un caractère unique est
trouvé. Il se souvient du dernier caractère qui est
attendu, et s'aperçoit rapidement qu'il n'y a pas ce caractère).
Si le masque utilisé est ((?>\D+)|<\d+>)*[!?]
les séquences de chiffres ne peuvent pas être
trouvées, et l'échec intervient rapidement.
Les sous-masques conditionnels
Il est possible de lier un sous-masque à une condition, ou de
choisir entre deux sous-masques alternatifs, en fonction du
résultat d'une assertion, ou suivant les résultats
de recherche précédents.
Les deux formes possibles de sous-masques conditionnels sont
(?(condition)masque positif) et
(?(condition) masque positif | masque négatif).
Si les conditions sont satisfaites, le masque positif est utilisé,
sinon, le masque négatif est utilisé, si présent.
S'il y a plus de deux alternatives, une erreur est générée
à la compilation.
Il y a deux types de conditions : si le texte entre les parenthèses
est une séquence de chiffres, alors la condition est satisfaite si
le sous-masque correspondant à ce numéro a réussi.
Considérons le masque suivant, qui contient des espaces non
significatifs pour le rendre plus compréhensible (on supposera
l'option PCRE_EXTENDED
activée) et qui est divisé en trois parties
pour simplifier les explications : ( \( )? [^()]+ (?(1) \) ).
La première partie recherche une parenthèse ouvrante
optionnelle, et si elle existe, elle est capturée. La deuxième
partie recherche un séquence de caractères qui ne contiennent
pas de parenthèses. La troisième partie est
conditionnée à la première, et s'assure que s'il
y avait une parenthèse ouvrante, il en existe une fermante.
Si une parenthèse ouvrante a été trouvée,
elle a été capturée, et donc la première capture
existe, et la condition est exécutée. Sinon, elle est
ignorée.
Ce masque recherche donc une séquence de lettres, éventuellement
placées entre parenthèse. Si la condition n'est pas une
séquence de chiffres, il faut que ce soit une assertion.
Ce peut être une assertion positive ou négative,
arrière ou avant. Considérons le masque suivant
(même conditions que le précédent) et avec deux
alternatives en seconde ligne :
(?(?=[^a-z]*[a-z])\d{2}[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ).
La condition est une assertion avant positive, qui recherche une
séquence optionnelle de caractères non-lettre. En d'autres
termes, elle teste la presence d'au moins une lettre dans la chaîne
sujet. Si une lettre est trouvée, la recherche se poursuit avec
la première alternative, et sinon, avec la seconde. Ce masque
recherche des chaînes de la forme dd-aaa-dd ou
dd-dd-dd, avec "aaa" qui sont des
lettres, et dd qui sont des chiffres.
Commentaires
La séquence (?# marque le début d'un commentaire,
qui se termine à la prochaine parenthèse fermante. Les
parenthèses imbriquées ne sont pas autorisées. Les
caractères entre ces délimiteurs ne jouent alors aucun rôle
dans le masque.
Si l'option PCRE_EXTENDED
est activée, les caractères dièses
# non échappés en dehors d'une classe de
caractères introduisent un commentaire qui continuera jusqu'à
la prochaine ligne dans le masque.
Masques récursifs
Considérons le cas où il faut recherche dans une
chaîne, avec un niveau d'imbrications infini de
parenthèses. Sans l'aide de la récursivité, le
mieux que nous puissions obtenir est de créer un masque avec un
niveau fixé de profondeur d'imbrication. Il n'est pas possible
de traiter des masques à niveau d'imbrications variable.
PCRE fournit un nouvel outil expérimental qui permet
d'utiliser la récursivité dans les masques (entre autre).
L'option (?R) est fournie pour servir la cause de
la récursivité. Le masque suivant résoud le
problème des parenthèses (l'option
PCRE_EXTENDED est
utilisée pour ignorer les espaces) :
\( ( (?>[^()]+) | (?R) )* \)
Tout d'abord, le masque recherche une parenthèse ouvrante. Puis,
il recherche n'importe quel nombre de sous-chaînes qui sont soit
des séquences de caractères non-parenthèses, ou
bien une recherche récursive avec le même masque (i.e.
une chaîne correctement incluse entre parenthèses).
Finalement, il recherche une parenthèse fermante.
Cet exemple particulier contient un nombre illimité de
répétitions imbriquées, ce qui fait que
l'utilisation de sous-chaînes à utilisation unique
pour rechercher les séquence de caractères
non-parenthèses est important, lorsqu'il s'applique à
une chaîne qui n'est pas valide. Par exemple, si on l'applique
à "(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()"
la réponse arrive rapidement. Sinon, si les sous-chaînes
à utilisation unique ne sont pas utilisées, la
recherche peut prendre un très long temps, car il existe
de très nombreuses combinaisons de + et
* à tester avant de conclure à
l'échec.
Les valeurs utilisées pour capturer les sous-masques sont celles
utilisées par les niveaux les plus hauts de
récursivités, auquel la valeur est fixée.
Si le masque précédent est utilisé avec
(ab(cd)ef) la valeur de la parenthèse
capturante est "ef", qui est la dernière
valeur lue au niveau supérieur. Si de nouvelles
parenthèses sont ajoutées, par exemple :
\( ( ( (?>[^()]+) | (?R) )* ) \)
alors la chaîne capturée est "ab(cd)ef",
c'est-à-dire le contenu de la parenthèses capturant
de plus haut niveau. S'il y a plus de 15 parenthèses
capturantes dans une chaîne, PCRE doit utiliser plus
de mémoire pour stocker ces données. S'il ne
peut obtenir cette mémoire supplémentaire, il ne fait
que sauver les 15 premières, car il n'y a pas moyen de
générer une erreur de mémoire lors d'une
récursion.
Performances
Certaines séquences de recherches sont plus efficaces que d'autres.
Ainsi, il est plus efficace d'utiliser une classe de caractères
telle que [aeiou] plutôt qu'une alternative
(a|e|i|o|u).
En général, le masque le plus simple, qui permette
la recherche désirée est le plus efficace. Le livre
de Jeffrey Friedl's contient de nombreuses études à
propos de l'optimisation des expressions régulières.
Lorsqu'un masque commence par.* et que l'option
PCRE_DOTALL est
activée, le masque est implicitement ancré par PCRE,
étant donné qu'il ne peut que rechercher au début
de la chaîne. Cependant, si option
PCRE_DOTALL n'est pas
activée, PCRE ne peut faire aucune optimisation car le
méta-caractères point "."
ne remplace pas une nouvelle ligne, et si la chaîne
sujet contient des nouvelles lignes, le masque peut trouver une
solution qui serait située juste après une
de ces nouvelles lignes, et non pas seulement au début
de la chaîne sujet. Par exemple, le masque,
(.*)second acceptera la chaîne
"premier \net second" (avec "\n"
qui remplace la nouvelle ligne), et la première chaîne
capturée sera "et".
Afin d'effectuer la recherche, PCRE va essayer d'appliquer le masque
à partir de chaque début de ligne. Si vous utilisez un
tel masque avec des chaînes qui ne contiennent pas de
caractères de nouvelles lignes, les meilleures performances
seront atteintes avec l'option
PCRE_DOTALL, ou en ancrant le
masque avec ^.*. Cela évite à PCRE
de scanner toute la chaîne pour rechercher un caractère
de nouvelle ligne et recommencer la recherche.
Attention aux masques qui contiennent des quantificateurs infinis
imbriqués. Ils peuvent demander un temps de calcul très
long, lorsqu'appliqués à une chaîne qui ne
correspond pas à ce masque. Par exemple, (a+)*
peut accepter "aaaa" de 33 manières
différentes, et ce nombre croit rapidement avec la taille
de la chaîne (le quantificateur * peut prendre
les valeurs de 0, 1, 2, 3, ou 4, et pour chaque cas non nul, le
quantificateur + peut prendre différentes
valeurs).
Lorsque le reste de la chaîne est tel que l'on s'achemine
vers un échec, PCRE doit en principe vérifier
toutes les possibilités, et cela prend un temps
extrêmement long. Un optmiseur repère les cas
les plus simples, tel que (a+)*b où
un caractère simple suit les quantificateurs. Avant de partir
dans les procédures standard de recherche, PCRE
s'assure qu'il y a au moins un "b" dans la
chaîne, et si ce n'est pas le cas, l'échec est
annoncé immédiatement. Sinon, il n'y a pas
d'optimisation dans la recherche. Vous pouvez voir la
différence de comportement avec le masque suivant :
(a+)*\d. Le premier retourne un échec
quasi-immédiatement, s'il est appliqué à
une ligne de "a", alors que le second masque
prend un temps significatif pour une chaîne de plus de
20 caractères.
|