¿Cómo puedo arreglar mi expresión regular para que no coincida demasiado con un cuantificador codicioso? [duplicar]

StackOverflow https://stackoverflow.com/questions/255815

Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Tengo la siguiente línea:

"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"

Lo analizo utilizando una expresión regular simple:

if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) {
    my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5);
}

Pero el; Al final arruina las cosas y no sé por qué. ¿No debería el operador codicioso manejar " todo " ;?

¿Fue útil?

Solución

El operador codicioso intenta agarrar la mayor cantidad de cosas que pueda y aún así emparejar la cadena. Lo que está sucediendo es que el primero (después de "decir") agarra "0ed673079715c343281355c2a1fde843; 2", el segundo toma "laka", el tercero se encuentra "hola". y el cuarto coincide con el paréntesis.

Lo que debes hacer es hacer que todos menos el último no sean codiciosos, por lo que se agarran lo menos posible y aún coinciden con la cadena:

(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)

Otros consejos

(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)

debería funcionar mejor

Aunque una expresión regular puede hacer esto fácilmente, no estoy seguro de que sea el enfoque más directo. Probablemente sea el más corto, pero en realidad no lo hace más fácil de mantener.

En cambio, sugeriría algo como esto:

$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)";

if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/)
{
    my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5;
    print join ",", map { "[

Aunque una expresión regular puede hacer esto fácilmente, no estoy seguro de que sea el enfoque más directo. Probablemente sea el más corto, pero en realidad no lo hace más fácil de mantener.

En cambio, sugeriría algo como esto:

[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)]

Esto resulta en:

<*>

Creo que esto es un poco más legible. No solo eso, creo que también es más fácil de depurar y mantener, porque esto se acerca más a cómo lo haría si un humano intentara lo mismo con lápiz y papel. Divida la cadena en trozos que luego puede analizar más fácilmente: haga que la computadora haga exactamente lo que usted haría. Cuando llegue el momento de hacer modificaciones, creo que a esta le irá mejor. YMMV.

]" } $ts,$command,$hash,$pid,$handle,$quote }

Esto resulta en:

<*>

Creo que esto es un poco más legible. No solo eso, creo que también es más fácil de depurar y mantener, porque esto se acerca más a cómo lo haría si un humano intentara lo mismo con lápiz y papel. Divida la cadena en trozos que luego puede analizar más fácilmente: haga que la computadora haga exactamente lo que usted haría. Cuando llegue el momento de hacer modificaciones, creo que a esta le irá mejor. YMMV.

Intente crear los primeros 3 (. *) ungreedy (.*?)

Si los valores en su lista delimitada por punto y coma no pueden incluir ningún punto y coma por sí mismos, obtendrá la expresión regular más eficiente y directa simplemente al deletrear eso. Si ciertos valores solo pueden ser, digamos, una cadena de caracteres hexadecimales, deletree eso. Las soluciones que usan un punto vago o codicioso siempre conducirán a un retroceso mucho inútil cuando la expresión regular no coincida con la cadena de asunto.

(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+)

Podría hacer que * no sea codicioso si agrega un signo de interrogación:

$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/

o puede hacer coincidir todo, excepto un punto y coma en cada parte, excepto la última:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top