• Publicidad

Perl en archivos de Texto

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Perl en archivos de Texto

Notapor Kiloko » 2007-10-22 10:35 @482

Buen día.

He estado buscando en Internet así como en algunos libros pero no logro encontrar la respuesta a este problema, y todo recae en el uso y modificación de archivos de texto.

Mi problemática es la siguiente:

Supongamos que yo tengo mi archivo X.dat y en el tengo información así;

Código: Seleccionar todo
10;11;12;13;14;15;16;17;18;19;20
21;22;23;24;25;26;27;28;29;30;31
32;33;34;35;36;37;38;39;40;41;42
43;44;45;46;47;48;49;50;51;52;53


Y quiero que Perl lea el primer renglón y lo guarde en un @nombre al cual le daré prioridad azul.

El segundo renglón se guarde en @nombre2 y le daré la prioridad verde.

Esto para tener
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@nombre1 (prioridad Azul)
@nombre2 (prioridad Verde)
@nombre3 (prioridad Roja)
@nombre4 (prioridad Negra)
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Lo hago así, para poder compararlo con un $numero que obtengo de otro archivo y así hacer la comparación:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$numero@nombre1.
$numero@nombre2.
$numero@nombre3.
$numero@nombre4.
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y digamos que coincide con @nombres3; entonces generar un archivo que diga: Roja. El fin de esto es que el rango de los números cambien (del archivo X.dat) por lo que se lee del archivo, pero lo que no cambia y lo que interesa son las etiquetas, roja, azul, verde, etcétera, (que se definen en el programa) que si coinciden generan un archivo con un mensaje como ven. ¿Alguna idea de cómo se podría lograr esto o algún tutorial que me recomienden?

Saludos.
:?:
Nunca interrumpas a tu enemigo cuando está cometiendo un error
Napoleón Bonaparte
Avatar de Usuario
Kiloko
Perlero nuevo
Perlero nuevo
 
Mensajes: 243
Registrado: 2007-07-10 18:26 @810
Ubicación: MOnterrey NL

Publicidad

Notapor Kiloko » 2007-10-22 12:46 @573

:D Sí se pudo, sí se pudo.

Pues no era tan difícil después de todo, así quedó el código: tenemos dos archivos; de los cuales extraemos información; de uno extraemos un solo campo que puede ir del 1 al 53 y del otro documento extraemos por párrafo, así que al momento de comparar se necesita hacer línea por línea, y si coinciden en la primera línea se despliega el mensaje que es amarilla, en la segunda, azul, y así hasta llegar a la roja,

Código: Seleccionar todo
10;11;12;13;14;15;16;17;18;19;20
21;22;23;24;25;26;27;28;29;30;31
32;33;34;35;36;37;38;39;40;41;42
43;44;45;46;47;48;49;50;51;52;53


Como ven el código, ¿algún comentario para poder hacerlo mas corto o de mejor forma?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open Data, "info.dat" or die "Error abrir datos.dat: $!\n";
my @fichero_A = <Data>;
open Data2, "datos.dat" or die "Error abrir datos.dat: $!\n";
my @fichero_B = <Data2>;
#--------------------------------------------
foreach $linea ( @fichero_A ) {
    $campo = ( split /:/, $linea )[3];

    foreach ( $fichero_B[0] ) { #10;11;12;13;14;15;16;17;18;19;20 Azul
        if ( m/ \b $campo \b /x ) {
            print 'Alarma Azul';
        }
    }
    #--------------------------------------------
    foreach $linea2 ( @fichero_A ) {
        $campo2 = ( split /:/, $linea2 )[3];

        foreach ( $fichero_B[1] ) { #21;22;23;24;25;26;27;28;29;30;31 Amarillo
            if ( m/ \b $campo2 \b /x ) {
                print 'Alarma Amarilla';
            }    
        }
 
        #------------------------------------------
        foreach $linea3 ( @fichero_A ) {
            $campo3 = ( split /:/, $linea3 )[3];

            foreach ( $fichero_B[2] ) { #32;33;34;35;36;37;38;39;40;41;42 Morado
                if ( m/ \b $campo3 \b /x ) {
                    print 'Alarma Morada';
                }    
            }
            #---------------------------------------------
            foreach $linea4 ( @fichero_A ) {
                $campo4 = ( split /:/, $linea4 )[3];

                foreach ( $fichero_B[3] ) { #43;44;45;46;47;48;49;50;51;52;53 Rojo
                    if ( m/ \b $campo4 \b /x ) {
                        print 'Alarma ROJA';
                    }    
                }
                close
            }
        }
    }
}
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Nunca interrumpas a tu enemigo cuando está cometiendo un error
Napoleón Bonaparte
Avatar de Usuario
Kiloko
Perlero nuevo
Perlero nuevo
 
Mensajes: 243
Registrado: 2007-07-10 18:26 @810
Ubicación: MOnterrey NL

Notapor explorer » 2007-10-22 12:53 @578

Lo único que te faltaba, de la solución dada en el otro hilo, es grabar el nivel de alarma en el fichero externo...

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

# Definimos los niveles de alarma
%niveles = (
    0 => 'Azul',
    1 => 'Verde',
    2 => 'Roja',
    3 => 'Negra',
);

# Leemos el malvado fichero X
@X = do { open X,"<X.dat" or die "ERROR al leer: $!\n"; <X> };

# El número a comparar
$numero = 11;

# Ver qué nivel de alerta tenemos
foreach $nivel ( 0 .. 3 ) {

    if ( $X[$nivel] =~ / \b $numero \b /x ) {   # Comparamos

        # Encontrado, actualizamos el nivel en el fichero externo
        open  S,">S.dat" or die "ERROR al escribir: $!\n";
        print S "$niveles{$nivel}\n";
        close S;

        last;    # No hace falta seguir buscando
    }
}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
El guardar cada renglón en una variable distinta no hace más que alargar la solución.

Por regla general, si en un problema vemos que necesitamos varias variables del tipo @nombre1, @nombre2, @nombre3,... es que seguramente necesitaremos usar un hash o array en lugar de tenerlas separadas.

En la solución propuesta, las líneas se guardan como elementos del array @X. Por eso luego podemos hacer un bucle por todas sus líneas con la variable $nivel, que nos servirá además para saber luego qué texto tenemos que escribir en el fichero externo, usándola como clave del hash %niveles, donde tenemos los mensajes de alarma.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Kiloko » 2007-10-22 14:56 @664

:? Comprendo que es lo que planteas y me parece buena idea el hacer externo el uso de las alarmas, pero me causa ruido, como se ingresaría en el código, ya que no veo la relación de los 2 archivos por ninguna, parte, digamos que descartamos el de valor = 11 pero el otro ? como hacer la relación de comparación para que después abra un archivo y lo guarde?
------------
También estoy notando que necesito agregar mas cosas, como la hora y datos similares, por lo que voy a necesitar hacer un programa estructurado, guardar variables y valores, que después pueda mandar llamar, algún tutorial que me recomiendes?
Saludos
Última edición por Kiloko el 2007-10-22 16:57 @748, editado 1 vez en total
Nunca interrumpas a tu enemigo cuando está cometiendo un error
Napoleón Bonaparte
Avatar de Usuario
Kiloko
Perlero nuevo
Perlero nuevo
 
Mensajes: 243
Registrado: 2007-07-10 18:26 @810
Ubicación: MOnterrey NL

Notapor explorer » 2007-10-22 16:49 @742

Hemos presentado la solución al mismo tiempo. Unos comentarios a la tuya:

* Estas leyendo los ficheros por líneas en sendos arrays. Pero luego haces un bucle muy extraño:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach ( $fichero_B[0] )
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Resulta que $fichero_B[0] es un SOLO elemento (la primera línea del fichero B), por lo que este bucle en realidad casi no lo es: solo lo ejecutamos una vez. Por lo tanto, no es necesario poner un bucle, reduciendo el problema a:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if ( $fichero_B[0] =~ m/ \b $campo \b /x ) {
    print 'Alarma Azul';
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


* Otro detalle peligroso... he editado tu código y si te fijas los bucles están anidados unos con otros, por lo estás ejecutando muchas decenas de bucles innecesarios. Es decir: el bucle de $linea4 se ejecuta por cada bucle de $linea3 que se ejecuta por cada bucle de $linea2. Debes des-anidar esos bucles.

* Una mejora sustancial es que los cuatro bucles foreach hacen casi lo mismo, así que es obvio que debe existir una forma de reducirlos a un caso común.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor explorer » 2007-10-22 16:50 @743

Kiloko escribiste::? Comprendo que es lo que planteas y me parece buena idea el hacer externo el uso de las alarmas, pero me causa ruido, como se ingresaría en el código, ya que no veo la relación de los 2 archivos por ninguna, parte, digamos que descartamos el de valor = 11 pero el otro ? como hacer la relación de comparación para que después abra un archivo y lo guarde?
Es que esa parte no está porque está ya puesta en la anterior respuesta en el otro hilo.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Kiloko » 2007-10-22 17:46 @782

:D jojo jo ya quedo, aunque sea solo la primera parte, ahora solo falta comparar los archivos que vaya creando, actualizarlos y hacer más exacta la consulta que se realice... bueno, espero esto sirva a los perleros; está también el uso de cómo se crea un archivo, cómo se ingresa la fecha, y cómo se guarda.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open Data, "info.dat" or die "Error abrir info.dat: $!\n";
my @fichero_A = <Data>;
open Data2, "datos.dat" or die "Error abrir datos.dat: $!\n";
my @fichero_B = <Data2>;
#--------------------------------------------
# Se introduce Tiempo..
($segundo,$minuto,$hora,$dia,$mes,$anio) = (localtime)[0,1,2,3,4,5,];
$anio+=1900; # Se suman 1900 ya que Debido a que perl se prepar para lo que sera el problema del 2000,    
$mes+=1;
$h= "$anio-$mes-$dia-$hora-$minuto"; #Tiempo para archivo
#-----------------------------------------------------------------
foreach $linea ( @fichero_A [0]) {
    $campo = ( split /=/, $linea )[5];
    $campo2 = ( split /=/, $linea )[0];

    if ( $fichero_B[0] =~ m/ \b $campo \b /x ) { #10;11;12;13;14;15;16;17;18;19;20 Azul {
        print "$campo2=$h =Alarma Azul\n";
        open (Data, ">>alarma.dat");
        print Data "$campo2=$h =Alarma Azul=\n";
        close(Data);  
    }
    if ( $fichero_B[1] =~ m/ \b $campo \b /x ) { #21;22;23;24;25;26;27;28;29;30;31 Amarilla
        print "$campo2=$h =Alarma Amarilla\n";
        open (Data, ">>alarma.dat");
        print Data "$campo2=$h =Alarma Amarilla=\n";
        close(Data);  
    }
    if ( $fichero_B[2] =~ m/ \b $campo \b /x ) { #32;33;34;35;36;37;38;39;40;41;42 Morada
        print "$campo2=$h =Alarma Morada\n";
        open (Data, ">>alarma.dat");
        print Data "$campo2=$h =Alarma Morada=\n";
        close(Data);  
    }
    if ( $fichero_B[3] =~ m/ \b $campo \b /x ) { #43;44;45;46;47;48;49;50;51;52;532 Roja
        print "$campo2=$h =Alarma roja\n";
        open (Data, ">>alarma.dat");
        print Data "$campo2=$h =Alarma Roja=\n";
        close(Data);  
    }          
 }
close
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

:D :D
Nunca interrumpas a tu enemigo cuando está cometiendo un error
Napoleón Bonaparte
Avatar de Usuario
Kiloko
Perlero nuevo
Perlero nuevo
 
Mensajes: 243
Registrado: 2007-07-10 18:26 @810
Ubicación: MOnterrey NL

Notapor explorer » 2007-10-22 18:25 @809

Pues no... el tener que sumar 1900 al número del año no tiene nada que ver con el efecto 2000. Viene de mucho atrás, de cuando se definieron las librerías estándar Unix.

En cuanto al programa presentado, veo que comparas cada campo extraído del fichero 'A' con todas las líneas del fichero B, con lo que es posible que un determinado campo genere más de una alarma en la misma pasada. ¿Eso es posible?

Lo pregunto porque en el fichero de ejemplo que has puesto el fichero B tenía 4 líneas distintas. Por eso en mi solución hay un last; para presentar solo el primer nivel encontrado.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$campo = ( split /=/, $linea )[5];
$campo2 = ( split /=/, $linea )[0];
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
se puede escribir como
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
($campo,$campo2) = (split /=/, $linea)[5,0];
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y reiterar lo dicho antes: con un hash reduces los 4 if a solo uno.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Kiloko » 2007-10-23 18:27 @810

En cuanto al programa presentado, veo que comparas cada campo extraído del fichero 'A' con todas las líneas del fichero B, con lo que es posible que un determinado campo genere más de una alarma en la misma pasada. ¿Eso es posible?

Estuve haciendo varias pruebas y no aparece tal error, espero que no pase, jajajaja
Lo estoy haciendo con hash pero le estoy agregando cosas nuevas... por cierto, ¿no sabrás cómo imprimir al final de una linea de texto?

Digamos, que se hace un archivo y sale algo como
Código: Seleccionar todo
12-10-2007=11
y
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$valor_uno # tiene el valor de 12
$valor_dos # tiene el valor de 10-2007
$valor_tres # tiene el valor de 11
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y nuevamente se genera el archivo en X tiempo pero quiero que al final solo se imprima $valor_tres (suponiendo que el valor de $valor_tres cambió de 11 a 130) (habría que leer nuevamente el archivo y posicionar el nuevo elemento en la última parte, pero no se me ocurre cómo).

Algo así tendría que salir:
Código: Seleccionar todo
12-10-2007=11=130

Saludos
Nunca interrumpas a tu enemigo cuando está cometiendo un error
Napoleón Bonaparte
Avatar de Usuario
Kiloko
Perlero nuevo
Perlero nuevo
 
Mensajes: 243
Registrado: 2007-07-10 18:26 @810
Ubicación: MOnterrey NL

Notapor explorer » 2007-10-23 19:18 @846

Kiloko escribiste:¿no sabrás cómo imprimir al final de una linea de texto?
Pues... imprimiendo...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print $linea_anterior, "=130\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados