Página 1 de 4

Problemas con expresión regular

NotaPublicado: 2007-04-23 02:13 @134
por rochi
Hola tengo que reconocer el siguiente patrón en un texto que viene en un archivo .txt. El patrón es la frase que comience en una nueva línea con "En los concursos .." (espacio en blanco después de 'concursos') y finalice con "." o ":". Esta frase puede ocupar más de una línea, ya que el "." podría encontrarse en la línea siguiente.
Este es el código, no sé qué hago mal porque solo despliega una oración, y no todas las que hay.

Gracias por cualquier sugerencia, aquí va el código.

Saludos.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$er_concursos = '^En los concursos\s.*(:|\.)';

if(scalar(@ARGV)>0)  # Compruebo que haya archivos
{

    foreach $file (@ARGV)  # Busca en todos los archivos
        {
            if(open(INFILE,$file))
                {
                       $file_aux = "";
                        while ($linea = <INFILE>)
                        {
                 $file_aux = $file_aux.$linea;   # Leemos todas las líneas y las metemos en una variable
                        }
                       close (INFILE);

                        print $er_concursos if ($file_aux =~ /$er_concursos/gsm)
                 }
                 else
                     {print "No se pudo abrir archivo $file\n";}
     }
}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

NotaPublicado: 2007-04-23 03:15 @177
por explorer
Bienvenido a los foros de Perl en Español.

El problema es el comodín glotón. Y que hay que pintar lo encontrado, no la expresión regular. Y repetir el proceso a lo largo de todo el fichero.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$er_concursos = qr/^(En los concursos\s.*?(:|\.))/ms;

local $/ = undef;

foreach $file (@ARGV) {             # Busca en todos los archivos
    open(INFILE,$file)
        or  print "No se pudo abrir archivo $file\n"
        and next;

    $file_aux = <INFILE>;           # Leemos todas las líneas y las metemos en una variable

    close INFILE;

    while ( $file_aux =~ /$er_concursos/g ) {
        print "$1\n";
    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Aunque no lo he probado, es básicamente lo que tenías hecho, con los siguientes cambios:
* Por notación y mejora de velocidad, $er_concursos la definimos como una expresión regular, no un string. Así la interpolación de la expresión regular se hace una sola vez en el programa y no una vez por cada ciclo.
* Indefinimos la variable $/ para que leamos todo el fichero en una única operación de lectura.
* Hacemos un bucle while con la expresión regular, para que nos dé todas las coincidencias posibles (con la ayuda de la opción /g) del patrón dentro del fichero.
* El cambio realizado en la expresión regular es colocar un '?' detrás de un comodín glotón (.*). De esta manera se queda con el patrón más corto que encuentre, no el más largo. Además se han colocado paréntesis de captura que nos devolverá nuestra frase en la variable $1.

NotaPublicado: 2007-04-23 16:04 @711
por rochi
Hola, me auto respondo. Era sustituir
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if ($file_aux =~ /$er_concursos/gsm)
            {
             print $1; print$2;
             #print "\n";
            }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

por
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
while ($file_aux =~ /$er_concursos/gsm)
            {
             print $1; print$2;
             #print "\n";
            }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Aún me entrevera el uso de /m y /s, cosas de novata.
Saludos

NotaPublicado: 2007-04-23 16:35 @733
por rochi
Por notación y mejora de velocidad, $er_concursos la definimos como una expresión regular, no un string. Así la interpolación de la expresión regular se hace una sola vez en el programa y no una vez por cada ciclo
¿Me podrias decir, o quien pueda responder, el concepto de interpolar?, no entendi demasiado.
Disculpen la pregunta, pero a medida que hago las cosas voy aprendiendo, saludos, y gracias una vez más.

NotaPublicado: 2007-04-23 18:02 @793
por explorer
Con lo de "interpolar" se refiere a que obtenemos el valor almacenado dentro de una variable o expresión, de forma 'indirecta'.

Ejemplo: si en la variable $casa tenemos el valor 'La casa de la abuela', cuando hacemos
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$casa = $casa . ' es azul.';
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

no estamos interpolando el valor almacenado en la variable. Sólo estamos haciendo una operación con ella (concatenar cadenas de caracteres). En cambio, si hacemos
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print "$casa es azul.";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

entonces decimos que, con la ayuda de las comillas dobles, estamos 'interpolando' (haciendo aparecer) el valor de la variable $casa dentro de toda la cadena de caracteres que están entrecomilladas.

Más información en man perlop, sección Quote and Quote-like Operators.

NotaPublicado: 2007-04-23 18:24 @808
por rochi
clarísimo, gracias

NotaPublicado: 2007-04-23 18:57 @831
por explorer
Ya está arreglado mi ejemplo. Había que cambiar la posición de la opción /g.

NotaPublicado: 2007-04-23 19:08 @839
por explorer
rochi escribiste:Aún me entrevera el uso de /m y /s, cosas de novata.
Las últimas recomendaciones sobre buenas prácticas en Perl recomiendan que siempre se use la combinación de opciones /xms, pues engloban las opciones más comunes para la mayor parte de las situaciones y más fáciles de entender por los nuevos programadores:
* /x : Se permite el uso del espacio en blanco para separar partes de la expresión regular.
* /m : Cambia el significado de '^' y '$'. En lugar de principio y fin del string se refieren a principio y fin de cada línea dentro de todo el string.
* /s : El comodín '.' puede localizar caracteres "\n". Que es lo mismo que decir que trata a todo el string como una sola línea.

Más información, en perlre.

NotaPublicado: 2007-04-23 20:34 @899
por rochi
Sigo con las expresiones regulares. Ahora debo filtrar aquellos nombres completos que comiencen con P y terminen en z.

Como Pablo Gomez, Pablo Sasz, Paz Ada Rodriguez, por ejemplo.
Por eso los siguientes nombres serían válidos:
Código: Seleccionar todo
Susana Gonzalez
Ema Sanchez
lucia rodriguez
Virginia Olague
Pirez Corrales


(Todos los nombres terminan con \n)

El tema es que con la expresión regular de abajo no toma Pirez Corrales, porque al estar Pirez rechaza al resto. O sea creo que estoy filtrando de más, porque Paz Ada Rodriguez lo filtra, pero debe ser por la palabra Paz.

Parte del código:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$expreg_nom = '([Nn]+[Oo]+[Mm]+[Bb]+[Rr]+[Ee]+ = )([^Pp](\w*|\s*)*[^Zz])(\n)';

  while ( $file_aux =~ /$expreg_nom/gm )
            {
               print "$2\n";
            }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Saludos, graciasssss

NotaPublicado: 2007-04-24 04:29 @228
por explorer
Para evitar tener que poner mayúsculas y minúsculas, usa la opción /i en la expresión regular.

Y en cuanto a la expresión regular... me parece que la has hecho demasiado complicada. Te aconsejo que la escribas tal cual has descrito el filtro.