Quantificateurs gourmands et paresseux
Découvrez comment fonctionnent les quantificateurs gourmands et paresseux en JavaScript : le mode gourmand consomme le maximum puis revient en arrière, tandis que le mode paresseux (*?, +?, ??, {n,m}?) prend le minimum.
Un quantificateur comme *, + ou ? indique à une expression régulière combien de fois le motif précédent peut se répéter. Mais lorsque plusieurs longueurs de texte différentes satisfont toutes le motif, le moteur doit décider laquelle choisir. C'est cette décision que contrôlent les quantificateurs gourmands et paresseux.
Par défaut, tout quantificateur est gourmand : il capture autant de caractères que possible. Ajoutez un ? après le quantificateur et il devient paresseux : il capture le moins possible. Choisir le mauvais mode est l'un des bugs les plus courants avec les expressions régulières — le symptôme classique est un motif qui « correspond à trop de texte ». Cette page explique le mécanisme derrière les deux modes pour que vous puissiez choisir le bon de manière délibérée.
Comment fonctionne réellement la correspondance gourmande : consommer, puis revenir en arrière
Un quantificateur gourmand ne sait pas magiquement où s'arrêter. Il fonctionne en deux phases :
- Consommer le maximum.
.*avale d'abord tout le reste de la chaîne. - Revenir en arrière. Si le motif qui suit
.*ne peut plus correspondre (parce que tout a déjà été consommé), le moteur rend les caractères un par un, en réessayant après chaque rendu, jusqu'à ce que l'ensemble du motif corresponde.
Ainsi, gourmand signifie « tout prendre, puis rendre à contrecœur le minimum nécessaire pour que le reste du motif réussisse ». Comprendre l'étape de retour en arrière est la clé pour prédire ce que font les motifs gourmands.
* gourmand en action
Ici .* correspond à n'importe quel caractère zéro fois ou plus. Comme rien n'est requis après lui, aucun retour en arrière n'est nécessaire et il conserve tout jusqu'à la fin de la ligne, produisant "ABCD*E".
+ gourmand en action
C+ correspond à "C" une fois ou plus et prend goulûment les trois occurrences, donc la correspondance est "ABCCC".
Comment fonctionne la correspondance paresseuse : consommer le minimum, puis s'étendre
Un quantificateur paresseux inverse la stratégie :
- Consommer le minimum.
.*?commence par ne rien correspondre. - S'étendre. Ce n'est que si le reste du motif échoue à correspondre que le moteur laisse le quantificateur paresseux prendre un caractère de plus, puis réessaie — en répétant jusqu'à ce que l'ensemble du motif réussisse.
Ainsi, paresseux signifie « prendre le moins possible, et croître seulement quand on y est forcé ». On rend n'importe quel quantificateur paresseux en ajoutant ? à sa suite.
*? paresseux en action
C'est le cas déroutant. Le résultat est simplement "AB". Pourquoi ? Parce que .*? est autorisé à ne rien correspondre, et il n'y a rien après lui dans le motif qui force une consommation supplémentaire. Dès que AB correspond, le motif est déjà complet, donc le quantificateur paresseux s'arrête volontiers à zéro caractère. Un quantificateur paresseux ne s'étend que lorsque quelque chose après lui — un délimiteur, un littéral, ou une ancre — l'y oblige.
+? paresseux en action
C+? doit correspondre à au moins un "C" (c'est ce qu'exige +), et rien après lui ne demande davantage, donc il s'arrête au premier : "ABC".
L'exemple canonique : <.*> vs <.*?>
La différence entre gourmand et paresseux est la plus facile à voir quand il y a quelque chose après le quantificateur. La correspondance des balises HTML est le cas d'école. Exécutez les deux motifs sur la même chaîne :
- Gourmand
/<.*>/correspond à"<p>Hello</p>"— toute la chaîne..*consomme tout, puis revient en arrière juste assez pour laisser un>au>final du motif, s'arrêtant sur le dernier>. - Paresseux
/<.*?>/correspond uniquement à"<p>"— une seule balise..*?s'étend caractère par caractère et s'arrête dès qu'il atteint le premier>.
Quand votre objectif est « correspondre à une seule balise », « correspondre à une seule chaîne entre guillemets », ou « correspondre jusqu'au prochain délimiteur », le mode paresseux est presque toujours ce qu'il vous faut.
La famille complète des quantificateurs paresseux
Chaque quantificateur gourmand a un jumeau paresseux formé en ajoutant ? :
| Gourmand | Paresseux | Signification de la forme paresseuse |
|---|---|---|
* | *? | Zéro fois ou plus, le moins possible |
+ | +? | Une fois ou plus, le moins possible |
? | ?? | Zéro ou une fois, préférer zéro |
{2,5} | {2,5}? | Entre 2 et 5, préférer 2 |
{2,} | {2,}? | Au moins 2, préférer 2 |
Notez que ?? n'est pas une faute de frappe : le premier ? est le quantificateur (zéro ou une fois) et le second le rend paresseux, donc il préfère ne rien correspondre quand il a le choix.
Quand utiliser les quantificateurs paresseux ?
Une règle pratique :
Utilisez un quantificateur paresseux quand vous souhaitez correspondre jusqu'à la première occurrence d'un délimiteur, et un quantificateur gourmand quand vous voulez tout jusqu'au dernier.
Situations courantes où le mode paresseux est le bon choix :
- Extraire une seule balise HTML/XML :
/<.*?>/. - Capturer le contenu d'un seul jeu de guillemets ou de crochets :
/".*?"/,/\(.*?\)/. - Récupérer du texte jusqu'au prochain séparateur sans déborder dans l'enregistrement suivant.
Deux mises en garde importantes :
- Un délimiteur est souvent plus clair que la paresse. Au lieu de
/".*?"/vous pouvez écrire/"[^"]*"/avec une classe de caractères niée. Cela évite entièrement le retour en arrière et est généralement plus rapide et plus prévisible. - Le mode paresseux a besoin de quelque chose sur quoi s'arrêter. Comme l'exemple
AB.*?l'a montré, un quantificateur paresseux en fin de motif (sans rien pour le faire avancer) se replie sur son minimum et correspond à presque rien. Associez-le à un littéral suivant, une ancre, ou un groupe capturant.
Résumé
- Les quantificateurs sont gourmands par défaut — ils prennent le maximum, puis reviennent en arrière pour que le reste du motif corresponde.
- Ajoutez
?pour rendre un quantificateur paresseux — il prend le minimum, puis s'étend seulement quand il y est contraint. - Un quantificateur paresseux sans rien après lui correspond au minimum légalement possible (souvent rien), donc donnez-lui toujours un délimiteur ou une ancre sur quoi s'arrêter.
- La famille complète des paresseux est
*?,+?,??et{n,m}?. - Utilisez le mode paresseux quand vous voulez « jusqu'au premier » délimiteur ; sinon, une classe de caractères niée est souvent le choix plus propre et plus rapide.