O que 'preguiçoso' e 'ganancioso' significam no contexto de expressões regulares?

Respostas:

644

O ganancioso consumirá o máximo possível. Em http://www.regular-expressions.info/repeat.html , vemos o exemplo de como tentar combinar tags HTML com <.+>. Suponha que você tenha o seguinte:

<em>Hello World</em>

Você pode pensar que <.+>( .meio qualquer caractere não de nova linha e +meio um ou mais ) só iria coincidir com o <em>e </em>, quando, na realidade, será muito gananciosos, e vão desde o primeiro <até o último >. Isso significa que corresponderá ao <em>Hello World</em>invés do que você queria.

Tornar preguiçoso ( <.+?>) impedirá isso. Ao adicionar o ?depois do +, dizemos para repetir o menor número de vezes possível , para que o primeiro >apareça, é onde queremos parar a correspondência.

Recomendamos que você baixe o RegExr , uma ótima ferramenta que o ajudará a explorar expressões regulares - eu o uso o tempo todo.

Sampson
fonte
2
então, se você usar ganancioso, você terá 3 (1 elemento + 2 tags) correspondências ou apenas 1 correspondência (1 elemento)?
ajsie
10
Combinaria apenas 1 vez, começando do primeiro < e terminando com o último > .
Sampson
3
Mas torná-lo preguiçoso corresponderia duas vezes, fornecendo a tag de abertura e fechamento, ignorando o texto no meio (já que não se encaixa na expressão).
Sampson
Outra ótima ferramenta que eu sempre uso: debuggex.com Ele também possui a função "Incorporar no StackOverflow".
Ron van der Heijden
8
Só para acrescentar que há uma maneira gananciosa de ir sobre ele, também: <[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan
302

'Ganancioso' significa corresponder a corda mais longa possível.

'Preguiçoso' significa corresponder a menor corda possível.

Por exemplo, os gananciosos h.+lpartidas 'hell'em 'hello'mas os preguiçosos h.+?lpartidas 'hel'.

slebetman
fonte
97
Brilhante, tão preguiçoso parará assim que a condição for satisfeita, mas ganancioso significa que só será interrompido quando a condição não for mais satisfeita?
Andrew S
3
Para todas as pessoas que leem o post: quantificadores gananciosos ou preguiçosos por si só não correspondem à substring mais longa / mais curta possível. Você precisaria usar um token ganancioso temperado ou usar abordagens que não sejam regex.
Wiktor Stribiżew
3
@ Andrews Não se confunda com o ll duplo no exemplo. É bastante preguiçoso corresponderá ao menor substring possível, enquanto ganancioso corresponderá ao maior tempo possível. Gananciosos h.+lpartidas 'helol'em 'helolo'mas os preguiçosos h.+?lpartidas 'hel'.
precisa saber é o seguinte
3
@ FloatingRock: No. x?significa xé opcional, mas +?é uma sintaxe diferente. Isso significa parar de cuidar de você encontrar algo que corresponda - correspondência lenta.
slebetman
1
@ FloatingRock: Quanto à forma como você diferencia as diferentes sintaxes, simple: ?significa opcional e +?significa preguiçoso. Portanto \+?significa +é opcional.
slebetman
113
+-------------------+-----------------+------------------------------+
| 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  |
+-------------------+-----------------+------------------------------+

Adicionar um? a um quantificador para torná-lo não-guloso, ou seja, preguiçoso.

Exemplo:
cadeia de teste: stackoverflow
expressão de registro ganancioso : s.*osaída: stackoverflo w
expressão lenta de registro : s.*?osaída: stacko verflow

Premraj
fonte
2
não é ?? equivalente a ? . Da mesma forma, não é {n}? equivalente a {n}
Number945 02/09
5
@BreakingBenjamin: no ?? não é equivalente a?, quando tiver a opção de retornar 0 ou 1 ocorrência, ele escolherá a alternativa 0 (lenta). Para ver a diferença, compare re.match('(f)?(.*)', 'food').groups()com re.match('(f)??(.*)', 'food').groups(). Neste último, (f)??não corresponderá ao 'f' principal, mesmo que pudesse. Portanto, o 'f' será correspondido pelo segundo grupo de captura '. *'. Tenho certeza de que você pode construir um exemplo com '{n}?' também. É certo que esses dois são muito raramente usados.
SMCI
55

Ganancioso significa que sua expressão corresponderá ao maior grupo possível, preguiçoso significa que corresponderá ao menor grupo possível. Para esta sequência:

abcdefghijklmc

e esta expressão:

a.*c

Uma partida gananciosa corresponderá a toda a cadeia e uma partida preguiçosa corresponderá apenas à primeira abc.

Carl Norum
fonte
16

Até onde eu sei, a maioria dos mecanismos de regex é gananciosa por padrão. Adicionar um ponto de interrogação no final do quantificador permitirá a correspondência lenta.

Como @Andre S mencionado no comentário.

  • Ganancioso: Continue pesquisando até que a condição não seja satisfeita.
  • Preguiçoso: Pare de procurar quando a condição for atendida.

Consulte o exemplo abaixo para saber o que é ganancioso e o que é preguiçoso.

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");
        }
    }
}


O resultado é:

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
Eugene
fonte
9

Retirado de www.regular-expressions.info

Ganância : Os quantificadores gananciosos primeiro tentam repetir o token o máximo de vezes possível e gradualmente desistem de correspondências à medida que o mecanismo recua para encontrar uma correspondência geral.

Preguiça : O quantificador preguiçoso primeiro repete o token quantas vezes for necessário e expande gradualmente a correspondência à medida que o mecanismo retorna pela regex para encontrar uma correspondência geral.

Suganthan Madhavan Pillai
fonte
6

Da expressão regular

Os quantificadores padrão nas expressões regulares são gananciosos, o que significa que eles correspondem o máximo possível, devolvendo apenas o necessário para corresponder ao restante da regex.

Usando um quantificador lento, a expressão tenta a correspondência mínima primeiro.

Adriaan Stander
fonte
4

Correspondência gananciosa. O comportamento padrão das expressões regulares é ser ganancioso. Isso significa que ele tenta extrair o máximo possível até estar em conformidade com um padrão, mesmo quando uma parte menor seria sintaticamente suficiente.

Exemplo:

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

Em vez de corresponder até a primeira ocorrência de '>', extraiu toda a cadeia. Esse é o comportamento padrão de ganância ou 'leve tudo' da regex.

A correspondência preguiçosa , por outro lado, "leva o mínimo possível". Isso pode ser efetuado adicionando um? no final do padrão.

Exemplo:

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

Se você deseja recuperar apenas a primeira correspondência, use o método de pesquisa.

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

Fonte: Exemplos de Regex do Python

Selva
fonte
3

Ganancioso significa que ele consumirá seu padrão até que não haja mais nenhum e não possa mais procurar.

O Lazy irá parar assim que encontrar o primeiro padrão solicitado.

Um exemplo comum que frequentemente encontro é \s*-\s*?de uma expressão regular([0-9]{2}\s*-\s*?[0-9]{7})

O primeiro \s*é classificado como ganancioso por causa *e parecerá o maior número possível de espaços em branco depois que os dígitos forem encontrados e, em seguida, procurará um caractere de traço "-". Onde o segundo \s*?é preguiçoso por causa do presente, *?significa que ele parecerá o primeiro caractere de espaço em branco e parará ali.

stackFan
fonte
3

Melhor mostrado pelo exemplo. Corda. 192.168.1.1e um regex ganancioso \b.+\b Você pode pensar que isso daria o primeiro octeto, mas na verdade corresponde a toda a cadeia. Por quê? Como o. + É ganancioso e uma correspondência gananciosa corresponde a cada caractere 192.168.1.1até atingir o final da string. Esta é a parte importante! Agora, ele começa a retroceder um caractere de cada vez até encontrar uma correspondência para o terceiro token ( \b).

Se a sequência de um arquivo de texto de 4 GB e 192.168.1.1 estivesse no início, você poderia ver facilmente como esse retorno causaria um problema.

Para tornar uma regex não gananciosa (preguiçosa), coloque um ponto de interrogação após sua pesquisa gananciosa, por exemplo

*?
??
+?

O que acontece agora é que o token 2 ( +?) encontra uma correspondência, a regex se move ao longo de um personagem e tenta o próximo token ( \b) em vez do token 2 ( +?). Então ele se arrasta cautelosamente.

Jason Alcock
fonte
0

Quantificadores gananciosos são como o IRS / ATO: eles levam o máximo que podem:

Se estiver lá, eles vão pegá-lo. Eles vão levar tudo:

Por exemplo, o IRS corresponde a este regex: .*

$50,000 - O IRS vai levar tudo. Esses gananciosos .*{4}?ers

Veja aqui um exemplo: regexr.com/4t27f

Quantificadores não gananciosos - eles levam o mínimo possível

Por outro lado, se eu pedir um reembolso de imposto, o IRS repentinamente se tornará não ganancioso e eles usarão esse quantificador:

(.{2}?)([0-9]*)contra esta expressão: $50,000O primeiro grupo não é carente e apenas corresponde $5- por isso recebo um $5reembolso. O resto é levado pelo tio Sam para ser desperdiçado.

Veja aqui: exemplo não ganancioso .

Porque se importar?

Torna-se importante se você estiver tentando corresponder a certas partes de uma expressão. Às vezes você não quer combinar tudo.

BKSpurgeon
fonte
-3

tente entender o seguinte comportamento:

    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
fonte