Respuestas:
Codicioso consumirá tanto como sea posible. En http://www.regular-expressions.info/repeat.html vemos el ejemplo de intentar hacer coincidir las etiquetas HTML con <.+>
. Supongamos que tiene lo siguiente:
<em>Hello World</em>
Puede pensar que <.+>
( .
significa cualquier personaje que no sea de nueva línea y +
significa uno o más ) solo coincidiría con el <em>
y el </em>
, cuando en realidad será muy codicioso, y pasará del primero <
al último >
. Esto significa que coincidirá en <em>Hello World</em>
lugar de lo que quería.
Hacerlo perezoso ( <.+?>
) evitará esto. Al agregar el ?
después del +
, le decimos que se repita la menor cantidad de veces posible , por lo que lo primero >
que aparece es dónde queremos detener la coincidencia.
Te animo a que descargues RegExr , una gran herramienta que te ayudará a explorar expresiones regulares. Lo uso todo el tiempo.
<[^>]+>
regex101.com/r/lW0cY6/1
'Codicioso' significa que coincida la cadena más larga posible
'Perezoso' significa una cadena más corta posible.
Por ejemplo, los codiciosos h.+l
partidos 'hell'
en 'hello'
pero los perezosos h.+?l
partidos 'hel'
.
h.+l
partidos 'helol'
en 'helolo'
pero los perezosos h.+?l
partidos 'hel'
.
x?
significa que x
es opcional pero +?
es una sintaxis diferente. Significa dejar de cuidar cuando encuentre algo que coincida: coincidencia perezosa.
?
significa opcional y +?
significa perezoso. Por \+?
lo tanto, los medios +
son opcionales.
+-------------------+-----------------+------------------------------+
| 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 |
+-------------------+-----------------+------------------------------+
Agrega un ? a un cuantificador para que no sea greedy, es decir, vago.
Ejemplo:
cadena de prueba: stackoverflow
expresión cod codiciosa : s.*o
salida: stackoverflo w
expresión reg perezosa : s.*?o
salida: stacko verflow
re.match('(f)?(.*)', 'food').groups()
con re.match('(f)??(.*)', 'food').groups()
. En el último, (f)??
no coincidirá con la 'f' principal, aunque podría. Por lo tanto, la 'f' coincidirá con el segundo grupo de captura '. *'. Estoy seguro de que puedes construir un ejemplo con '{n}?' también. Es cierto que estos dos se usan muy raramente.
Codicioso significa que su expresión coincidirá con el grupo más grande posible, perezoso significa que coincidirá con el grupo más pequeño posible. Para esta cadena:
abcdefghijklmc
y esta expresión:
a.*c
Una coincidencia codiciosa coincidirá con toda la cadena, y una coincidencia perezosa coincidirá solo con la primera abc
.
Hasta donde yo sé, la mayoría de los motores de expresiones regulares son codiciosos por defecto. Agregar un signo de interrogación al final del cuantificador habilitará la coincidencia diferida.
Como @Andre S mencionó en el comentario.
Consulte el siguiente ejemplo para saber qué es codicioso y qué es perezoso.
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
Tomado de www.regular-expressions.info
Codicia : los cuantificadores codiciosos primero intentan repetir la ficha tantas veces como sea posible, y gradualmente abandona las coincidencias a medida que el motor retrocede para encontrar una coincidencia general.
Pereza : el cuantificador perezoso primero repite el token tantas veces como sea necesario y expande gradualmente la coincidencia a medida que el motor retrocede a través de la expresión regular para encontrar una coincidencia general.
Los cuantificadores estándar en las expresiones regulares son codiciosos, lo que significa que coinciden tanto como pueden, solo devuelven lo necesario para que coincida con el resto de la expresión regular.
Al usar un cuantificador diferido, la expresión intenta primero la coincidencia mínima.
Juego codicioso. El comportamiento predeterminado de las expresiones regulares es ser codicioso. Eso significa que intenta extraer lo más posible hasta que se ajuste a un patrón, incluso cuando una parte más pequeña hubiera sido sintácticamente suficiente.
Ejemplo:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
En lugar de coincidir hasta la primera aparición de '>', extrajo la cadena completa. Este es el comportamiento codicioso o "tómalo todo" predeterminado de regex.
La combinación perezosa , por otro lado, "toma lo menos posible". Esto puede realizarse agregando un?
al final del patrón.
Ejemplo:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
Si solo desea recuperar la primera coincidencia, utilice el método de búsqueda.
re.search('<.*?>', text).group()
#> '<body>'
Fuente: Python Regex Ejemplos
Codicioso significa que consumirá su patrón hasta que no quede ninguno y no pueda buscar más.
Lazy se detendrá tan pronto como encuentre el primer patrón que solicitó.
Un ejemplo común que a menudo encuentro es \s*-\s*?
una expresión regular.([0-9]{2}\s*-\s*?[0-9]{7})
El primero \s*
se clasifica como codicioso debido a *
que buscará tantos espacios en blanco como sea posible después de que se encuentren los dígitos y luego busque un carácter de guión "-". Donde como el segundo \s*?
es perezoso debido al presente, *?
significa que se verá el primer carácter de espacio en blanco y se detendrá allí.
Se muestra mejor con el ejemplo. Cuerda. 192.168.1.1
y una expresión regular codiciosa. \b.+\b
Puede pensar que esto le daría el primer octeto, pero en realidad coincide con toda la cadena. ¿Por qué? Porque. + Es codicioso y una coincidencia codiciosa coincide con cada personaje 192.168.1.1
hasta que llega al final de la cadena. Esta es la parte importante! Ahora comienza a retroceder un personaje a la vez hasta que encuentre una coincidencia para la tercera ficha ( \b
).
Si la cadena de un archivo de texto de 4GB y 192.168.1.1 estaba al principio, podría ver fácilmente cómo este retroceso podría causar un problema.
Para hacer una expresión regular no codiciosa (perezosa) ponga un signo de interrogación después de su búsqueda codiciosa, por ejemplo
*?
??
+?
Lo que sucede ahora es que la ficha 2 ( +?
) encuentra una coincidencia, la expresión regular se mueve a lo largo de un personaje y luego prueba la siguiente ficha ( \b
) en lugar de la ficha 2 ( +?
). Entonces se arrastra con cautela.
Si está allí, vendrán y lo tomarán. Se lo llevarán todo:
Por ejemplo, el IRS coincide con esta expresión regular: .*
$50,000
- El IRS lo tomará todo. Esos codiciosos .*{4}?
ERS
Vea aquí para ver un ejemplo: regexr.com/4t27f
Por otro lado, si solicito un reembolso de impuestos, el IRS de repente se vuelve no codicioso y usan este cuantificador:
(.{2}?)([0-9]*)
en contra de esta expresión: $50,000
el primer grupo no es necesitado y solo coincide $5
, por lo que obtengo un $5
reembolso. El resto lo toma el tío Sam para gastarlo malgastamente.
Ver aquí: ejemplo no codicioso .
Se vuelve importante si está tratando de hacer coincidir ciertas partes de una expresión. A veces no quieres igualar todo.
intenta comprender el siguiente comportamiento:
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); // ""