regex - repetitions - ¿Qué significa ''perezoso'' y ''codicioso'' en el contexto de las expresiones regulares?
regex repetitions (11)
¿Podría alguien explicar estos dos términos de una manera comprensible?
Codicioso significa que consumirá tu patrón hasta que no quede ninguno y no pueda seguir buscando.
Lazy se detendrá tan pronto como encuentre el primer patrón que solicitó.
Un ejemplo común que encuentro a menudo es /s*-/s*?
de una expresión regular ([0-9]{2}/s*-/s*?[0-9]{7})
La primera /s*
se clasifica como codiciosa debido a *
y se verá con 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 por el presente de *?
lo que significa que se verá el primer carácter de espacio en blanco y se detendrá allí.
Codicioso significa que su expresión coincidirá con el grupo más grande posible, perezosa significa que coincidirá con el grupo más pequeño posible. Para esta cadena:
abcdefghijklmc
y esta expresión:
a.*c
Un partido codicioso coincidirá con toda la cadena, y un partido perezoso solo coincidirá con el primer abc
.
Los cuantificadores estándar en expresiones regulares son codiciosos, lo que significa que coinciden tanto como pueden, y solo devuelven lo necesario para que coincida con el resto de la expresión regular.
Al usar un cuantificador perezoso, la expresión intenta primero la coincidencia mínima.
Intenta entender 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); // ""
Por lo que 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 perezosa.
Como @Andre S menciona en el comentario.
- Codicioso: Sigue buscando hasta que la condición no se cumpla.
- Lazy: dejar de buscar una vez que se cumpla la condición.
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");
}
}
}
El resultado es:
Estoy greeedy y quiero 100000000 dólares. Esto es lo máximo que puedo conseguir.
Soy demasiado perezoso para ganar tanto dinero, solo 100 dólares es suficiente para mí
Se muestra mejor con el ejemplo. Cuerda. 192.168.1.1 y un regex codicioso / b. + / B Puede pensar que esto le daría el primer octeto, pero en realidad coincide con toda la cadena. ¡¡¡POR QUÉ!!! Debido a que. + Es codicioso y una coincidencia codiciosa coincide con todos los caracteres en ''192.168.1.1'' hasta que llega al final de la cadena. Esto es lo importante! Ahora comienza a retroceder un carácter a la vez hasta que encuentra una coincidencia para el tercer token (/ 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 el token 2 (+?) Encuentra una coincidencia, la expresión regular se mueve a lo largo de un carácter y luego intenta el siguiente token (/ b) en lugar del token 2 (+?). Así que se arrastra con cautela.
Tomado de www.regular-expressions.info
Avaricia : los cuantificadores codiciosos primero intentan repetir el token tantas veces como sea posible, y gradualmente renuncian a las coincidencias a medida que el motor retrocede para encontrar una coincidencia general.
La pereza : el cuantificador perezoso primero repite la ficha tantas veces como sea necesario, y gradualmente expande la coincidencia a medida que el motor retrocede a través de la expresión regular para encontrar una coincidencia general.
"Codicioso" significa unir la cuerda más larga posible.
''Lazy'' significa hacer coincidir la cadena más corta posible.
Por ejemplo, la codiciosa h.+l
coincide con ''hell''
en ''hello''
pero la perezosa h.+?l
coincide con ''hel''
.
Coincidencia codiciosa. El comportamiento predeterminado de las expresiones regulares es ser codicioso. Eso significa que intenta extraer tanto como sea 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 hacer coincidir hasta la primera aparición de ''>'', extrajo toda la cadena. Este es el comportamiento codicioso predeterminado o "tómalo todo" de las expresiones regulares.
El emparejamiento perezoso , por otro lado, ''toma lo menos posible''. Esto puede efectuarse añadiendo un ?
Al final del patrón.
Ejemplo:
re.findall(''<.*?>'', text)
#> [''<body>'', ''</body>'']
Si solo desea recuperar la primera coincidencia, use el método de búsqueda en su lugar.
re.search(''<.*?>'', text).group()
#> ''<body>''
Fuente: Python Regex Ejemplos
Los codiciosos consumirán tanto como sea posible. Desde http://www.regular-expressions.info/repeat.html vemos el ejemplo de intentar hacer coincidir las etiquetas HTML con <.+>
. Supongamos que tienes lo siguiente:
<em>Hello World</em>
Puede pensar que <.+>
( .
Significa que cualquier carácter que no sea de nueva línea y +
significa uno o más ) solo coincidiría con <em>
y </em>
, cuando en realidad será muy codicioso, e irá desde el primer <
hasta el último >
. Esto significa que coincidirá con <em>Hello World</em>
lugar de con lo que querías.
Hacerlo perezoso ( <.+?>
) Evitará esto. Añadiendo el ?
después del +
, le pedimos que lo repita la menor cantidad de veces posible , por lo que el primero que aparece es donde queremos detener el emparejamiento.
Le animo a que descargue RegExr , una gran herramienta que lo ayudará a explorar Expresiones regulares: lo uso todo el tiempo.
+-------------------+-----------------+------------------------------+
| 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 sea ungreedy es decir perezoso.
Ejemplo:
cadena de prueba:
codiciosa expresión reg : s.*o
salida: stackoverflo w
expresión lenta de reg : s.*?o
salida: stacko verflow