Respostas:
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.
<[^>]+>
regex101.com/r/lW0cY6/1
'Ganancioso' significa corresponder a corda mais longa possível.
'Preguiçoso' significa corresponder a menor corda possível.
Por exemplo, os gananciosos h.+l
partidas 'hell'
em 'hello'
mas os preguiçosos h.+?l
partidas 'hel'
.
h.+l
partidas 'helol'
em 'helolo'
mas os preguiçosos h.+?l
partidas 'hel'
.
x?
significa x
é opcional, mas +?
é uma sintaxe diferente. Isso significa parar de cuidar de você encontrar algo que corresponda - correspondência lenta.
?
significa opcional e +?
significa preguiçoso. Portanto \+?
significa +
é opcional.
+-------------------+-----------------+------------------------------+
| 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.*o
saída: stackoverflo w
expressão lenta de registro : s.*?o
saída: stacko verflow
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.
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
.
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.
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");
}
}
}
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
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.
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.
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
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.
Melhor mostrado pelo exemplo. Corda. 192.168.1.1
e 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.1
até 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.
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
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,000
O primeiro grupo não é carente e apenas corresponde $5
- por isso recebo um $5
reembolso. O resto é levado pelo tio Sam para ser desperdiçado.
Veja aqui: exemplo não ganancioso .
Torna-se importante se você estiver tentando corresponder a certas partes de uma expressão. Às vezes você não quer combinar tudo.
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); // ""