
Correspondance « gourmande » vs « paresseuse » en expressions régulières : pourquoi votre motif capture trop de caractères
Publié le 24 juil. 2026
Vous écrivez <b>.*</b> pour extraire le contenu d’une balise de gras, vous le testez sur <b>Hello</b>, et cela fonctionne parfaitement. Ensuite, vous l’exécutez sur du code HTML réel comportant deux balises de gras sur la même ligne — <b>Hello</b> and <b>World</b> — et au lieu d’obtenir deux correspondances, vous obtenez une seule correspondance géante couvrant les deux balises. Ce n’est pas un bug de votre moteur d’expressions régulières ; c’est le comportement par défaut de *, + et {n,m}, et il suffit d’un seul caractère pour y remédier une fois que vous comprenez ce qui se passe.
Pourquoi .* capture plus que prévu
Par défaut, les quantificateurs dans les expressions régulières sont gloutons — .* ne signifie pas « trouver quelques caractères », mais « trouver autant de caractères que possible, puis ne reculer que si le reste du motif l’exige absolument ».
Examinons étape par étape la comparaison entre <b>.*</b> et <b>Hello</b> and <b>World</b>:
<b>correspond au premier<b>..*commence par consommer tout le reste de la chaîne — tout ce qui se trouve jusqu’à la fin, y compris le deuxième<b>World</b>.- Le moteur doit ensuite trouver
</b>pour terminer la correspondance ; il commence donc à remonter depuis la fin de.*, un caractère à la fois. - Le premier emplacement (en parcourant la chaîne à rebours depuis la fin) où
</b>s’insère est le tout dernier</b>de la chaîne — et non le premier où il devrait « logiquement » s’arrêter.
La correspondance finit donc par être <b>Hello</b> and <b>World</b> dans son intégralité, car la correspondance « gourmande » essaie toujours d’abord la chaîne la plus longue possible et ne la raccourcit que le strict minimum nécessaire pour que le reste du motif aboutisse.
La solution : rendre le quantificateur « paresseux » avec ?
L’ajout d’un ? immédiatement après un quantificateur le fait passer de « glouton » à « paresseux » (également appelé « non glouton » ou « réticent ») : *?, +?, ??, {n,m}?.
Un quantificateur « paresseux » fait l’inverse : il commence par faire correspondre le moins de caractères possible, puis ne s’étend que si le reste du motif ne peut pas encore aboutir.
<b>.*?</b> appliqué à la même chaîne :
<b>correspond au premier<b>..*?commence par faire correspondre zéro caractère.- Le moteur vérifie : est-ce que
</b>correspond à cet endroit précis ? Non (nous en sommes à « Hello… », pas encore à un</b>) — il étend donc.*?d’exactement un caractère et vérifie à nouveau. - Ce processus se répète caractère par caractère jusqu’à ce que
.*?ait consommé exactementHello, moment auquel</b>correspond immédiatement.
Résultat : <b>Hello</b> et <b>World</b> sont renvoyés comme deux correspondances distinctes, ce qui correspond presque toujours à ce que l’on souhaite réellement lors de l’analyse de structures de type balises ou délimiteurs.
Quand vous souhaitez réellement utiliser l’approche gloutonne (ce n’est pas simplement « une mauvaise valeur par défaut »)
L’approche gloutonne n’est pas une erreur du langage — elle est correcte pour un cas différent, tout aussi courant : la correspondance avec la limite la plus externe d’un élément, et non avec la plus petite unité à l’intérieur de celui-ci. Si vous extrayez « tout ce qui se trouve entre le premier { et le dernier } » dans un bloc de texte de type JSON (par exemple, pour récupérer un objet entier indépendamment de l’imbrication), l’approche « greedy » est tout à fait appropriée, tandis que l’approche « lazy » s’arrêterait au premier } intérieur, vous donnant ainsi un fragment tronqué et invalide.
Règle générale : « lazy » pour les petits blocs délimités qui se répètent (balises, chaînes entre guillemets, éléments de liste) ; « greedy » pour « récupérer l’intégralité de la portée externe ».
Référence rapide
| Motif | Comportement | À utiliser lorsque |
|---|---|---|
.*, .+, {n,m} |
Greedy — correspond au plus long possible | Vous voulez la portée la plus externe, ou s’il n’y a qu’une seule correspondance dans la chaîne |
.*?, .+?, {n,m}? |
Paresseux — correspond à la plus courte possible | Vous avez plusieurs segments délimités similaires et souhaitez les extraire séparément |
Si vous n’êtes pas sûr du comportement réel d’un motif sur votre entrée réelle plutôt que sur votre chaîne de test, l’exécuter sur le texte multi-correspondance réel dans un testeur d’expressions régulières avec mise en évidence des correspondances en temps réel rendra la différence immédiatement visible — vous verrez un seul bloc géant mis en évidence pour le mode « greedy », contre plusieurs blocs distincts pour le mode « lazy », ce qui est généralement plus rapide que de raisonner caractère par caractère.