Que signifient «paresseux» et «gourmand» dans le contexte des expressions régulières?

Réponses:

644

Les gourmands consommeront autant que possible. De http://www.regular-expressions.info/repeat.html nous voyons l'exemple d'essayer de faire correspondre les balises HTML avec <.+>. Supposons que vous ayez les éléments suivants:

<em>Hello World</em>

Vous pouvez penser que <.+>( .signifie n'importe quel caractère non nouveau et +signifie un ou plusieurs ) ne correspondrait qu'au <em>et au </em>, alors qu'en réalité il sera très gourmand et ira du premier <au dernier >. Cela signifie qu'il correspondra à la <em>Hello World</em>place de ce que vous vouliez.

Le rendre paresseux ( <.+?>) empêchera cela. En ajoutant l' ?after the +, nous lui disons de répéter le moins de fois possible , donc la première fois >qu'il apparaît, c'est là que nous voulons arrêter la correspondance.

Je vous encourage à télécharger RegExr , un excellent outil qui vous aidera à explorer les expressions régulières - je l'utilise tout le temps.

Sampson
la source
2
donc si vous utilisez gourmand u aura 3 correspondances (1 élément + 2 balises) ou juste 1 correspondance (1 élément)?
ajsie
10
Il ne correspondrait qu'à 1 fois, à partir du premier < et se terminant par le dernier > .
Sampson
3
Mais le rendre paresseux correspondrait deux fois, nous donnant à la fois les balises d'ouverture et de fermeture, ignorant le texte entre les deux (car il ne correspond pas à l'expression).
Sampson
Un autre excellent outil que j'utilise toujours: debuggex.com Il a également une fonction "Embed on StackOverflow".
Ron van der Heijden
8
Juste pour ajouter qu'il y a aussi une manière gourmande de s'y prendre: <[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan
302

«Gourmand» signifie correspondre à la chaîne la plus longue possible.

«Paresseux» signifie correspondre à la chaîne la plus courte possible.

Par exemple, les avides h.+lmatchs 'hell'dans 'hello'mais les paresseux h.+?lmatchs 'hel'.

Slebetman
la source
97
Brillant, donc paresseux s'arrêtera dès que la condition l sera satisfaite, mais gourmand signifie qu'il ne s'arrêtera qu'une fois que la condition l ne sera plus satisfaite?
Andrew S
3
Pour toutes les personnes qui lisent le post: les quantificateurs gourmands ou paresseux ne correspondent pas en eux-mêmes à la sous-chaîne la plus longue / la plus courte possible. Vous devez utiliser soit un jeton gourmand tempéré , soit utiliser des approches non regex.
Wiktor Stribiżew
3
@AndrewS Ne soyez pas dérouté par le double ll dans l'exemple. C'est plutôt paresseux correspondra à la sous-chaîne la plus courte possible tandis que gourmand correspondra à la plus longue possible. Greedy h.+lmatchs 'helol'dans 'helolo'mais les paresseux h.+?lmatchs 'hel'.
v.shashenko
3
@FloatingRock: Non. x?Moyen xest facultatif mais +?est une syntaxe différente. Cela signifie cesser de chercher après avoir trouvé quelque chose qui correspond - une correspondance paresseuse.
slebetman
1
@FloatingRock: Quant à la façon dont vous différenciez les différentes syntaxes, simple: ?signifie facultatif et+? signifie paresseux. Le \+?moyen +est donc facultatif.
slebetman
114
+-------------------+-----------------+------------------------------+
| Greedy quantifier | Lazy quantifier |        Description           |
+-------------------+-----------------+------------------------------+
| *                 | *?              | Star Quantifier: 0 or more   |
| +                 | +?              | Plus Quantifier: 1 or more   |
| ?                 | ??              | Optional Quantifier: 0 or 1  |
| {n}               | {n}?            | Quantifier: exactly n        |
| {n,}              | {n,}?           | Quantifier: n or more        |
| {n,m}             | {n,m}?          | Quantifier: between n and m  |
+-------------------+-----------------+------------------------------+

Ajouter un ? à un quantificateur pour le rendre indigne, c'est-à-dire paresseux.

Exemple:
chaîne de test: expression de reg glouton stackoverflow :
s.*o sortie: stackoverflo w
expression de reg paresseux : s.*?osortie: stacko verflow

Premraj
la source
2
n'est pas ?? équivalent à ? . De même, n'est-ce pas {n}? équivalent à {n}
Number945
5
@BreakingBenjamin: non ?? n'est pas équivalent à?, quand il a le choix de renvoyer 0 ou 1 occurrence, il choisira l'alternative 0 (paresseux). Pour voir la différence, comparez re.match('(f)?(.*)', 'food').groups()à re.match('(f)??(.*)', 'food').groups(). Dans ce dernier, (f)??ne correspondra pas au «f» de tête, même s'il le pourrait. Par conséquent, le «f» sera mis en correspondance avec le deuxième groupe de capture «. *». Je suis sûr que vous pouvez construire un exemple avec '{n}?' aussi. Certes, ces deux-là sont très rarement utilisés.
smci
55

Gourmand signifie que votre expression correspondra au plus grand groupe possible, paresseux signifie qu'il correspondra au plus petit groupe possible. Pour cette chaîne:

abcdefghijklmc

et cette expression:

a.*c

Un match gourmand correspondra à toute la chaîne et un match paresseux ne correspondra qu'à la première abc.

Carl Norum
la source
16

Pour autant que je sache, la plupart des moteurs d'expression régulière sont gourmands par défaut. Ajouter un point d'interrogation à la fin du quantificateur permettra une correspondance paresseuse.

Comme @Andre S l'a mentionné dans le commentaire.

  • Gourmand: Continuez à chercher jusqu'à ce que la condition ne soit pas remplie.
  • Paresseux: arrêtez de chercher une fois que la condition est remplie.

Reportez-vous à l'exemple ci-dessous pour savoir ce qui est gourmand et ce qui est paresseux.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String args[]){
        String money = "100000000999";
        String greedyRegex = "100(0*)";
        Pattern pattern = Pattern.compile(greedyRegex);
        Matcher matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm greeedy and I want " + matcher.group() + " dollars. This is the most I can get.");
        }

        String lazyRegex = "100(0*?)";
        pattern = Pattern.compile(lazyRegex);
        matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
        }
    }
}


Le résultat est:

I'm greeedy and I want 100000000 dollars. This is the most I can get.

I'm too lazy to get so much money, only 100 dollars is enough for me
Eugène
la source
9

Tiré de www.regular-expressions.info

Gourmandise : les quantificateurs gourmands essaient d' abord de répéter le jeton autant de fois que possible, et abandonnent progressivement les correspondances à mesure que le moteur revient en arrière pour trouver une correspondance globale.

Paresse : le quantificateur paresseux répète d'abord le jeton aussi peu de fois que nécessaire, et étend progressivement la correspondance au fur et à mesure que le moteur revient sur l'expression régulière pour trouver une correspondance globale.

Suganthan Madhavan Pillai
la source
6

De l' expression régulière

Les quantificateurs standard dans les expressions régulières sont gourmands, ce qui signifie qu'ils correspondent autant qu'ils le peuvent, ne donnant en retour que nécessaire pour correspondre au reste de l'expression régulière.

En utilisant un quantificateur paresseux, l'expression essaie d'abord la correspondance minimale.

Adriaan Stander
la source
4

Correspondance gourmande. Le comportement par défaut des expressions régulières est d'être gourmand. Cela signifie qu'il essaie d'extraire autant que possible jusqu'à ce qu'il soit conforme à un modèle, même si une plus petite partie aurait été syntaxiquement suffisante.

Exemple:

import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']

Au lieu de correspondre jusqu'à la première occurrence de '>', il a extrait la chaîne entière. C'est le comportement par défaut gourmand ou «tout prendre» de l'expression régulière.

L'appariement paresseux , en revanche, «prend le moins possible». Cela peut être effectué en ajoutant un? à la fin du motif.

Exemple:

re.findall('<.*?>', text)
#> ['<body>', '</body>']

Si vous souhaitez que seule la première correspondance soit récupérée, utilisez plutôt la méthode de recherche.

re.search('<.*?>', text).group()
#> '<body>'

Source: Exemples Python Regex

Selva
la source
3

Gourmand signifie qu'il consommera votre modèle jusqu'à ce qu'il n'en reste plus et qu'il ne puisse pas chercher plus loin.

Lazy s'arrêtera dès qu'il rencontrera le premier motif que vous avez demandé.

Un exemple courant que je rencontre souvent est celui \s*-\s*?d'une expression régulière([0-9]{2}\s*-\s*?[0-9]{7})

Le premier \s*est classé comme gourmand à cause de *et cherchera autant d'espaces blancs que possible une fois les chiffres rencontrés, puis recherchera un tiret "-". Alors que le second \s*?est paresseux à cause du présent *?qui signifie qu'il regardera le premier caractère d'espace blanc et s'arrêtera juste là.

stackFan
la source
3

Mieux montré par l'exemple. Chaîne. 192.168.1.1et un regex gourmand \b.+\b Vous pourriez penser que cela vous donnerait le 1er octet mais correspond en fait à la chaîne entière. Pourquoi? Parce que le. + Est gourmand et qu'une correspondance gourmande correspond à chaque caractère 192.168.1.1jusqu'à ce qu'il atteigne la fin de la chaîne. C'est le bit important! Maintenant, il commence à revenir en arrière un personnage à la fois jusqu'à ce qu'il trouve une correspondance pour le 3e jeton (\b ).

Si la chaîne un fichier texte de 4 Go et 192.168.1.1 était au début, vous pouvez facilement voir comment ce retour en arrière pourrait causer un problème.

Pour rendre un regex non gourmand (paresseux) mettez un point d'interrogation après votre recherche gourmande par exemple

*?
??
+?

Ce qui se passe maintenant, c'est que le jeton 2 ( +?) trouve une correspondance, l'expression régulière se déplace le long d'un personnage, puis essaie le prochain jeton ( \b) plutôt que le jeton 2 ( +?). Alors, ça avance avec précaution.

Jason Alcock
la source
0

Les quantificateurs gourmands sont comme l'IRS / ATO: ils en prennent autant qu'ils le peuvent:

S'il est là, ils viendront le prendre. Ils vont tout prendre:

Par exemple, l'IRS correspond à cette expression régulière: .*

$50,000 - L'IRS prendra tout. Ces .*{4}?ers gourmands

Voir ici pour un exemple: regexr.com/4t27f

Quantificateurs non gourmands - ils en prennent aussi peu que possible

D'un autre côté, si je demande un remboursement d'impôt, l'IRS devient soudainement non gourmand, et ils utilisent ce quantificateur:

(.{2}?)([0-9]*)contre cette expression: $50,000Le premier groupe n'est pas dans le besoin et ne correspond qu'à $5- donc je reçois un $5remboursement. Le reste est pris par l'oncle Sam pour être gaspillé.

Voir ici: Exemple non gourmand .

Pourquoi s'embêter?

Cela devient important si vous essayez de faire correspondre certaines parties d'une expression. Parfois, vous ne voulez pas tout faire correspondre.

BKSpurgeon
la source
-3

essayez de comprendre le comportement suivant:

    var input = "0014.2";

Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"

input = " 0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"

input = "  0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""
FrankyHollywood
la source