7.89.9.1 Détails sur les expressions régulières
7.89.9 syntaxe des masques
7.89 Expressions régulières compatibles Perl
7 Index des fonctions
Manuel PHP
. Introduction . Méta-caractères . Antislash . Accent circonflexe et Dollar . Point . Crochets . Barre verticale . Options internes . Sous-masques . Répétitions . Références arrières . Assertions ->Sous-masques uniques . Les sous-masques conditionnels . Commentaires . Masques récursifs . Performances
|
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.
|