Masques récursifs
Considérons le cas où il faut rechercher 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'imbrication variable.
PCRE fournit un nouvel outil expérimental qui permet
d'utiliser la récursivité dans les masques (entre autres).
L'option (?R)
est fournie pour servir la cause de
la récursivité. Le masque suivant résout 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équences 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 temps très long, 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é, auxquels 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èse capturante
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 dans le cadre d'une récursivité.
(?1)
, (?2)
et suivants
peuvent être également utilisés pour les sous masques récursifs. Il est également
possible d'utiliser les sous masques nommés : (?P>foo)
ou
(?&name)
.
Si la syntaxe pour une référence de sous-masque récursif (soit par un
nombre ou par un nom) est utilisée en dehors des parenthèses à laquelle
elle fait référence, il opère comme une sous-routine dans un langage
de programmation. Un exemple ci-dessus a montré que le masque
(sens|respons)e and \1ibility
trouvera "sense and sensibility"
et
"response and responsibility"
, mais pas
"sense and responsibility"
. Si on utilise plutôt le masque
(sens|respons)e and (?1)ibility
alors, il trouvera "sense and responsibility"
tout comme les deux autres chaînes.
De telles références doivent, dépendant, suivre le sous-masque auquel
elles se réfèrent.
La longueur maximale d'un sujet correspond au plus grand nombre positif
qu'une variable entière peut contenir. Cependant, PCRE utilise la récursivité
pour gérer les sous-masques et les répétitions infinies. Ce qui signifie
que l'espace disponible pour la pile peut limiter la taille du sujet qui peut
être passé à certains masques.