Respondí esta pregunta en SuperUser que estaba relacionada con el tipo de expresiones regulares que se usaban al agrupar una salida.
La respuesta que di fue esta:
tail -f log | grep "some_string.*some_string"
Y luego, en tres comentarios a mi respuesta, @Bob escribió esto:
.*
es codicioso y puede capturar más de lo que quieres..*?
Suele ser mejor.
Luego esto,
el
?
es un modificador activado*
, lo que lo hace perezoso en lugar del codicioso predeterminado. Asumiendo PCRE.
Busqué en Google PCRE
, pero no pude entender cuál es el significado de esto en mi respuesta.
y finalmente esto,
También debo señalar que esto es regex (grep haciendo POSIX regex por defecto), no un shell glob.
Solo sé qué es un Regex y su uso muy básico en el comando grep. Entonces, no pude obtener ninguno de esos 3 comentarios y tengo estas preguntas en mente:
- ¿Cuáles son las diferencias en el uso de
.*?
frente.*
? - ¿Cuál es mejor y bajo qué circunstancia? Por favor proporcione ejemplos.
También sería útil entender los comentarios, si alguien pudiera
ACTUALIZACIÓN: Como respuesta a la pregunta ¿En qué se diferencia Regex de Shell Globs? @Kusalananda proporcionó este enlace en su comentario.
NOTA: Si es necesario, lea mi respuesta a esta pregunta antes de responder para consultar el contexto.
fuente
.*
vs..*?
La pregunta "diferencia entre expresiones regulares y globos de shell" ya se ha abordado en este sitio.Respuestas:
Ashok ya señaló la diferencia entre
.*
y.*?
, así que solo proporcionaré información adicional.grep
(suponiendo que la versión GNU) admite 4 formas de unir cadenas:grep
usa BRE por defecto.BRE y ERE están documentados en el capítulo Expresiones regulares de POSIX y PCRE está documentado en su sitio web oficial . Tenga en cuenta que las características y la sintaxis pueden variar entre las implementaciones.
Vale la pena decir que ni BRE ni ERE admiten la pereza :
Entonces, si desea usar esa función, deberá usar PCRE en su lugar:
Editar 1
.*
se usa para hacer coincidir el patrón "más largo" 1 posible..*?
se utiliza para hacer coincidir el patrón "más corto" 1 posible.En mi experiencia, el comportamiento más buscado suele ser el segundo.
Por ejemplo, supongamos que tenemos la siguiente cadena y solo queremos hacer coincidir las etiquetas html 2 , no el contenido entre ellas:
Ahora compara
.*
vs.*?
:1. El significado de "más largo" y "más corto" en un contexto de expresiones regulares es un poco complicado, como señaló Kusalananda . Consulte la documentación oficial para más información.
2. No se recomienda analizar html con regex . Este es solo un ejemplo con fines educativos, no lo use en la producción.
fuente
.*
vs.*?
?Supongamos que tomo una cadena como:
can cats eat plants?
El uso de codicioso
c.*s
coincidirá con toda la cadena, ya que comienzac
y termina cons
, siendo un operador codicioso, continúa coincidiendo hasta la aparición final de s.Mientras que usar el vago
c.*?s
solo coincidirá hasta que se encuentre la primera aparición des
, es decir, cadenacan cats
.A partir del ejemplo anterior, es posible que pueda reunir eso:
"Codicioso" significa hacer coincidir la cadena más larga posible. "Perezoso" significa hacer coincidir la cadena más corta posible. Adición de una
?
a un cuantificador como*
,+
,?
, o{n,m}
hace que sea perezoso.fuente
cats
, por lo que no se aplica estrictamente "lo más corto posible" en ese sentido.Una cadena podría coincidir de varias maneras (de simple a más compleja):
Como una cadena estática (Suponga var = '¡Hola Mundo!'):
shell
[ "$var" = "Hello World!" ] && echo yes
grep
echo "$var" | grep -F "Hello"
bash
grep -F "Hello" <<<"$var"
Como un pegote:
shell
echo ./*
# enumera todos los archivos en pwd. golpe de
concha
case $var in (*Worl*) echo yes;; (*) echo no;; esac
[[ "$var" == *"Worl"* ]] && echo yes
Hay globos básicos y extendidos. El
case
ejemplo usa globos básicos. El[[
ejemplo bash usa globos extendidos. La primera coincidencia de archivo podría ser básica o extendida en algún shell como la configuraciónextglob
en bash. Ambos son idénticos en este caso. Grep no podía usar globos.El asterisco en un globo significa algo diferente a un asterisco en una expresión regular :
Glob
* matches any number (including none) of
cualquier personaje .regex
* matches any number (including none) of the
elemento anterior .Como una expresión regular básica (BRE):
sed
echo "$var" | sed 's/W.*d//'
# print: ¡Hola!
grep
grep -o 'W.*d' <<<"$var"
# print World!
No hay BRE en shells (básicos) o awk.
Expresiones regulares extendidas (ERE):
bash
[[ "$var" =~ (H.*l) ]]
# match: Hola Worl
sed
echo "$var" | sed -E 's/(d|o)//g'
# print: Hell Wrl!
awk
awk '/W.*d/{print $1}' <<<"$var"
# print: Hola
grep
grep -oE 'H.*l' <<<"$var"
# print: Hola Worl
Expresiones regulares compatibles con Perl:
grep
grep -oP 'H.*?l
# print: Hel
Solo en un PCRE a
*?
tiene algún significado de sintaxis específica.Hace que el asterisco sea perezoso (sin gracia): pereza en lugar de avaricia .
Esto es solo la punta del iceberg, hay codiciosos, perezosos , dóciles o posesivos . También hay mirar hacia adelante y hacia atrás, pero no se aplican al asterisco
*
.Hay una alternativa para obtener el mismo efecto que una expresión regular no codiciosa:
La idea es muy simple: no use un punto
.
, niegue el siguiente carácter para que coincida[^o]
. Con una etiqueta web:Lo anterior debería aclarar completamente todos los comentarios de @Bob 3. Parafraseando:
.*
es codicioso.*?
no lo es.Preguntas
¿Cuáles son las diferencias en el uso de. ? vs. ?
.*?
es válido solo en sintaxis PCRE..*
es más portátil.[^a]*
¿Cuál es mejor y bajo qué circunstancia? Por favor proporcione ejemplos.
¿Mejor? Depende de la meta. No hay mejor, cada uno es útil para diferentes propósitos. He proporcionado varios ejemplos arriba. ¿Necesitas más?
fuente