Regular Expressions
Quantificateurs gourmands et paresseux
Recherche…
Paramètres
Quantificateurs | La description |
---|---|
? | Faites correspondre le caractère ou la sous-expression précédent 0 ou 1 fois (de préférence 1). |
* | Faites correspondre le caractère précédent ou la sous-expression 0 ou plusieurs fois (autant que possible). |
+ | Faites correspondre le caractère précédent ou la sous-expression 1 ou plusieurs fois (autant que possible). |
{n} | Faites correspondre le caractère ou la sous-expression précédent exactement n fois. |
{min,} | Faites correspondre le caractère précédent ou la sous-expression min ou plusieurs fois (autant que possible). |
{0,max} | Faites correspondre le caractère précédent ou la sous-expression max ou moins (le plus près possible de max ). |
{min,max} | Correspondre au caractère précédent ou sous - expression d' au moins min fois , mais pas plus de fois maximum (aussi près que possible max). |
Quantificateurs paresseux | La description |
?? | Faites correspondre le caractère ou la sous-expression précédent 0 ou 1 fois (de préférence 0). |
*? | Faites correspondre le caractère précédent ou la sous-expression 0 ou plusieurs fois (le moins possible). |
+? | Faites correspondre le caractère précédent ou la sous-expression 1 fois ou plus (le moins possible). |
{n}? | Faites correspondre le caractère ou la sous-expression précédent exactement n fois. Aucune différence entre les versions gourmandes et paresseuses. |
{min,}? | Faites correspondre le caractère précédent ou la sous-expression min ou plusieurs fois (aussi près que possible de min ). |
{0,max}? | Faites correspondre le caractère précédent ou la sous-expression max ou moins (le moins possible). |
{min,max}? | Faites correspondre le caractère ou la sous-expression précédente avec les temps minimum , mais pas plus que les durées maximales (aussi proches que possible de min ). |
Remarques
Cupidité
Un quantificateur gourmand essaie toujours de répéter le sous-modèle autant de fois que possible avant d’explorer des correspondances plus courtes par retour en arrière.
Généralement, un motif gourmand correspondra à la plus longue chaîne possible.
Par défaut, tous les quantificateurs sont gourmands.
Paresse
Un quantificateur paresseux (également appelé non-gourmand ou réticent ) tente toujours de répéter le sous-modèle aussi peu de fois que possible, avant d'explorer les correspondances plus longues par expansion.
Généralement, un modèle paresseux correspond à la chaîne la plus courte possible.
Pour rendre les quantificateurs paresseux, ajoutez-les simplement ?
au quantificateur existant, par exemple +?
, {0,5}?
.
Le concept de gourmandise et de paresse n'existe que dans les moteurs de retour en arrière
La notion de quantificateur gourmand / paresseux n'existe que dans le backtracking des moteurs de regex. Dans les moteurs de regex non-backtracking ou les moteurs regex conformes à POSIX, les quantifiers spécifient uniquement la limite supérieure et la limite inférieure de la répétition, sans spécifier comment trouver la correspondance - ces moteurs correspondront toujours à la plus longue chaîne de gauche.
La cupidité et la paresse
Compte tenu de l'entrée suivante:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
Nous allons utiliser deux modèles: un gourmand: A.*Z
, et un paresseux: A.*?Z
Ces modèles donnent les résultats suivants:
-
A.*Z
donne 1 correspondance:AlazyZgreeedyAlaaazyZ
(exemples: Regex101 , Rubular ) -
A.*?Z
donne 2 correspondances:AlazyZ
etAlaaazyZ
(exemples: Regex101 , Rubular )
Commencez par vous concentrer sur ce que fait A.*Z
Quand il correspond au premier A
, le .*
, Étant gourmand, essaie alors de correspondre autant .
comme possible.
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\________________________/
A.* matched, Z can't match
Étant donné que le Z
ne correspond pas, les retours en arrière du moteur et .*
Doivent alors correspondre à un de moins .
:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\_______________________/
A.* matched, Z can't match
Cela se produit encore quelques fois, jusqu'à ce qu'il arrive à ceci:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\__________________/
A.* matched, Z can now match
Maintenant, Z
peut correspondre, donc le motif global correspond à:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\___________________/
A.*Z matched
En revanche, la répétition (paresseuse) réticente dans A.*?Z
correspond au premier peu .
que possible, puis en prendre plus .
le cas échéant. Cela explique pourquoi il trouve deux correspondances dans l'entrée.
Voici une représentation visuelle de la correspondance entre les deux motifs:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\____/l \______/l l = lazy
\_________g_________/ g = greedy
Exemple basé sur la réponse apportée par les polygenélubrifiants .
Le standard POSIX n'inclut pas le ?
opérateur, tant de moteurs de regex POSIX n'ont pas de correspondance paresseuse. Bien que le refactoring, en particulier avec le "plus grand tour de passe-passe" , puisse aider dans certains cas, le seul moyen d'avoir une correspondance parfaite est d'utiliser un moteur qui le supporte.
Limites avec plusieurs correspondances
Lorsque vous avez une entrée avec des limites bien définies et que vous attendez plus d'une correspondance dans votre chaîne, vous avez deux options:
- Utiliser des quantificateurs paresseux;
- Utiliser une classe de caractère négatif.
Considérer ce qui suit:
Vous avez un moteur de template simple, vous voulez remplacer des sous-chaînes comme $[foo]
où foo
peut être n'importe quelle chaîne. Vous voulez remplacer cette sous-chaîne par celle qui est basée sur la partie comprise entre []
.
Vous pouvez essayer quelque chose comme \$\[(.*)\]
, Puis utiliser le premier groupe de capture.
Le problème avec ceci est si vous avez une chaîne comme something $[foo] lalala $[bar] something else
votre match sera
something $[foo] lalala $[bar] something else
| \______CG1______/|
\_______Match______/
Le groupe de capture étant foo] lalala $[bar
qui peut être ou ne pas être valide.
Vous avez deux solutions
Utiliser la paresse: Dans ce cas, faire
*
lazy est une façon de trouver les bonnes choses. Donc, vous changez votre expression en\$\[(.*?)\]
En utilisant la classe de caractère négatif:
[^\]]
vous modifiez votre expression en\$\[([^\]]*)\]
.
Dans les deux solutions, le résultat sera le même:
something $[foo] lalala $[bar] something else
| \_/| | \_/|
\____/ \____/
Le groupe de capture étant respectivement foo
et bar
.
L'utilisation de la classe de caractères nuls réduit le problème de retour en arrière et peut économiser beaucoup de temps à votre processeur lorsqu'il s'agit de grandes entrées.