Général

Les PCRE

Les POSIX

Pratique

Linux

Spécial php

Les billets de fred

Optimisation sur Expreg.com


Quelques conseils d'optimisation pour vos expressions régulières.

1) Attention à l'utilisation du dot !

 Dans la majorité des regex que je rencontre sur le net, vous êtes tous tentés, et c'est compréhensible, d'utiliser le dot qui prend tous les caractères, sauf le retour à la ligne.

Si l'usage de ce métacarctère est très simple, il faut bien avouer qu'il impose au moteur de regex de faire des recherches sur un nombre considérable de combinaisons.
Logique, le dot prend tout.

Pour cette raison, il est bien plus intéressant de travailler avec des classes complémentées qui, en dehors d'être d'une efficacité redoutable, vont s'avérer d'une rapidité étonnante.
Contrairement au dot qui est gourmand par défaut, un classe négative ne l'est pas.
En clair, avec une classe complémentée (négative) la recherche s'arrêtera dès que le premier caractère "négativé" sera rencontré.

C'est le nombre de backtracking (retour arrière en lecture) qui essouffle le moteur de regex.
Maintenant, ne me faites pas dire ce que je n'ai pas dit :
Si l'usage de la classe complémentée est dans une majorité de cas préférable, ce n'en est pas pour autant la panacée.

2) Une classe plutôt qu'une alternative !

Une classe est bien plus rapide qu'une alternative. C'est pour cette raison que je vous conseille dans la mesure du possible de toujours préférer la classe à l'alternative.

Devant une alternative, le moteur de regex aura le comportement suivant :
- il prend les alternatives les unes après les autres en commençant par la première et teste chacune d'entre-elles jusqu'au moment où il trouvera la concordance qu'il recherche.
dès cet instant il s'arrêtera et laissera les autres alternatives sur le côté.

En connaissant ce comportement il vous est donc facile de prévoir l'alternative qui aura le plus de chance d'être reconnue le plus tôt dans la chaîne afin de limiter le travail du moteur de regex.
Je vous donne un exemple.
$ch='Pif Bof Paf Bip Pof';
preg_match_all('`(p(?:a|i|o)f)`i',$ch,$out);
echo'
'; 
print_r($out);
echo'
';
?>
$ch='Pif Bof Paf Bip Pof';
preg_match_all('`(p[aio]f)`i',$ch,$out);
echo'
'; 
print_r($out);
echo'
';
?>
Les deux afficheront :
Array
(
[0] => Array
(
[0] => Pif
[1] => Paf
[2] => Pof
)

[1] => Array
(
[0] => Pif
[1] => Paf
[2] => Pof
)

)
mais la deuxième sera 3 à 4 fois plus rapide que la première
Aide-mémoire :
  • Une classe peut être complémentée, l'alternative ne le peut pas.
  • Une classe de caractère reconnaît exactement un caractère, peu importe la longueur de la liste qu'elle comporte.
  • Une alternative par contre peu reconnaître des termes de longueur différente, chacun étant indépendant de l'autre.
  • Une classe de caractères est toujours une assertion positive, elle doit absolument reconnaître un caractère pour réussir.
    Cf-> Assertion

3) Les parenthèses capturantes... non-capturantes !

Dans la mesure du possible, si vous ne devez pas capturer certaines parties de votre masque, rendez vos parenthèses (alternative) non capturante.
Dans le masque de l'exemple ci-dessus, vous remarquerez que je l'ai fait grâce à ?:
comme ceci : '`(p(?:a|i|o)f)`i'
En faisant comme cela, vous allégez la charge de moteur de regex et vous rendez vos regex plus rapide.

4) Vos masques de regex sont complexes ? Scindez-les !


Evitez de faire des regex monstrueuses, longues, compliquées dans lesquelles les alternatives sont nombreuses, etc...

Il est, selon mon expérience personnelle, bien plus efficace de réduire une regex complexe en deux ou trois de taille plus petite. Sans mettre en avant le niveau de performance qui sera très souvent meilleur (hé oui le moteur de regex ne devra pas analyser des dizaines de niveau), des petites regex seront bien plus facile à lire ou a relire.

Dans une regex, plus le motif est complexe, plus les combinaisons possibles augmenteront de manière considérable.

Optimisation de vos regex... à suivre !

ADAM Benjamin 2008 | Admin