• Publicidad

Leer y reemplazar cadena 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.

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-10 14:55 @663

A ver ahora...

Lo he simplificado al máximo, quitando todas las expresiones regulares.
Sabiendo ya cómo son realmente los archivos que hay que procesar, ya podemos dar una solución muy optimizada.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;                                     # estilo estricto
  3. use warnings;                                   # activar advertencias
  4. use diagnostics;                                # diagnósticos de fallos
  5. use autodie;                                    # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  6.  
  7. ### Variables
  8. my %redes;                                      # almacén con los cambios
  9. my %agentes = (
  10.     Juan    => '22333444X',
  11.     Antonio => '11111119H',
  12. );
  13. my $agentes = join "|", keys %agentes;          # construimos una expresión regular
  14. $agentes    = qr/\b($agentes)\b/;
  15.  
  16. ### Lectura del archivo CSV
  17. open my $CSV, '<', 'archivo.csv';
  18.  
  19. while (<$CSV>) {                                # para cada línea, hasta fin de archivo
  20.     chomp;                                      # quitamos caracteres fin de línea
  21.     my($red, $nombre) = split /[;]/;            # partimos la línea, extraemos columnas
  22.  
  23.     $redes{$red} = $nombre;
  24. }
  25.  
  26. close $CSV;
  27.  
  28. ### Procesado
  29. open my $ARCHIVO, '<', 'archivo.txt';                   # Lectura del archivo a tratar
  30. open my $SALIDA,  '>', 'archivo.new.txt';               # Escritura del archivo resultado
  31.  
  32. <$ARCHIVO> for 1 .. 6;                                  # saltamos la cabecera
  33.  
  34. while (my $linea = <$ARCHIVO>) {                        # para cada línea del $ARCHIVO
  35.     my(@campos) = split " ", $linea, 4;                 # partir en cuatro cachos
  36.  
  37.     my $IP      = $campos[2];
  38.     my $red     = substr $IP, 0, 1 + rindex $IP, '.';   # extraemos la red /24 a la que pertenece $IP
  39.  
  40.     ## Sustitución del nombre de la red
  41.     if (exists $redes{$red}) {                          # si podemos cambiarla
  42.         $campos[2] = $redes{$red};                      # la cambiamos
  43.     }
  44.  
  45.     ## Sustitución de la descripción
  46.     if ($campos[3] =~ /$agentes/) {                     # buscamos los agentes dentro del campo cuarto
  47.         $campos[3] = qq("$agentes{$1}"\n);              # lo cambiamos por el NIF
  48.     }
  49.  
  50.     print $SALIDA join " ", @campos;                    # guardamos el resultado
  51. }
  52.  
  53. close   $ARCHIVO;
  54. close   $SALIDA;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
La salida ahora es
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
2013-05-31 09:00:15 Sede_Cantabria 22333444X
2013-05-31 09:00:18 Sede_Leon 11111119H
2013-05-31 09:00:21 Sede_Cantabria 22333444X
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

También usamos un método para acelerar la búsqueda de agentes: los metemos todos en una expresión regular que vamos construyendo de esta manera:

/\b(Juan|Antonio)\b/

De esa manera, lo que hacemos es buscar por todos los agentes a la vez, dentro del campo cuarto. Si encontramos alguno, queda capturado en $1 gracias a los paréntesis, y lo usaremos como clave en la línea siguiente para rehacer el cuarto campo con el NIF correspondiente.

Total: un bucle menos y mayor velocidad de procesado.

Y aún se puede aumentar las velocidades: comentar las líneas 'use strict' y 'use warnings' cuando sabemos que el programa está libre de errores.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Re: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-11 05:20 @264

Muchas gracias, explorer.

Yo había hecho otro script para sacar la red del cliente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;                            # estilo estricto
  3. use warnings;                          # activar advertencias
  4. use diagnostics;                       # diagnósticos de fallos
  5. use autodie;                           # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  6.  
  7. ### Procesado
  8. open my $ARCHIVO, '<', 'archivo.txt';  # Lectura del archivo a tratar
  9. open my $SALIDA,  '>', 'archivo.new.txt';    # Escritura del archivo resultado
  10.  
  11. for ( 1 .. 6 ) {                       # Saltamos las lineas de cabecera
  12.                                        #<$ARCHIVO>;
  13.     my $linea = <$ARCHIVO>;
  14.     print $SALIDA $linea;
  15. }
  16. while ( my $linea = <$ARCHIVO> ) {     # para cada línea del $ARCHIVO
  17.     my $pos_blanco = ( index $linea, ' ', 20 ) + 1;
  18.     my $pos_punto  = ( index $linea, ".", 27 ) + 1;
  19.     my $long_host  = $pos_blanco - $pos_punto - 1;
  20.     my $long_IP    = $pos_blanco - 21;
  21.     my $long_Red   = $long_IP - $long_host;
  22.     my (@campos) = split " ", $linea, 4;
  23.     my $IP = $campos[2];
  24.     $campos[2] = substr( $IP, 0, $long_Red );
  25.     print $SALIDA join " ", @campos;   # guardamos el resultado
  26. }
  27. close $ARCHIVO;
  28. close $SALIDA;
  29.  
  30. qx(perl final.pl);
  31.  
  32.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


y llamar posteriormente al script final.pl. Pero obviamente con un peor rendimiento que el que tú propones :wink:

Muchas gracias por vuestras aportaciones, me han enseñado mucho. Gracias y hasta el próximo hilo.
Última edición por explorer el 2013-06-11 05:32 @272, editado 1 vez en total
Razón: Formateado de código con Perltidy
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-11 06:11 @299

He modificado mi última versión para agregar el salto de las seis lineas de la cabecera.

Me interesaría saber lo siguiente:
  • diferencia de velocidad entre el script Perl y el programa en Visual Basic
  • diferencia de número de líneas
  • diferencia en el tamaño del programa (el archivo de texto del programa Perl y el ejecutable terminado en Visual Basic)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-11 06:18 @304

Perdón, me queda una cosa.

No me guarda el NIF entrecomillado...
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-11 06:33 @315

Arreglada la línea 48.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-11 06:54 @329

Perdón de nuevo. Ya está solucionado el tema de las comillas.

explorer: recopilo los datos que pides y te los paso. Pero ya te adelanto que la diferencia es abismal...

Una cosa: Has ordenado los agentes inversamente... ¿Con qué fin?
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-11 07:03 @335

Pues... en principio... no haría falta...

La idea original era que, al ordenador los nombres de los agentes en orden inverso, el motor de expresiones regulares coloca "Juanito" delante de "Juan", y así, tenemos una garantía adicional a la hora de buscar el nombre del agente y no confundir uno con el otro.

Pero como estamos usando las anclas '\b', ya no es necesario.

Nada, nada... puedes quitar 'reverse sort'.

Irá aún más rápido. :)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-11 11:45 @531

Hola, explorer.

He quitado el 'reverse sort' y sigue funcionando bien.

Pero tengo un problema con el script. Hasta ahora estaba analizando una columna de texto donde salía el nombre de usuario y lo cambiaba por su DNI. Pero ahora me piden que analice también la columna de User-agent para buscar el SO, y es donde veo el problema.

Necesito que la búsqueda y reemplazo se haga en el orden en que defino el hash:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %agentes = ( # Definimos los agentes a identificar y cambiar
  2.     Android => 'Android',
  3.     Linux => 'Linux',
  4.     Windows => 'Windows',
  5.     MSIE => 'Windows',
  6. );
  7.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

porque el campo que contiene Android, también contiene Linux, pero me lo ha de reemplazar por Android y no por Linux. No sé si me explico. Y me parece que al hacer
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $agentes = join "|", keys %agentes;          # construimos una expresión regular
  2. $agentes    = qr/\b($agentes)\b/;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

no somos capaces de respetar ese orden, o bien si encuentra dos $agentes en la misma línea, sustituye el último, porque he detectado líneas que contienen "Android", y al reemplazar, lo cambia por "Linux". ¿Hay alguna forma de que al construir la expresión regular se respete ese orden?

Saludos,
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-11 15:58 @707

Menudo problema... en el User-Agent, podemos encontrarnos de todo.

Es más: no hay NINGUNA garantía de que lo que dice el User-Agent sea cierto. De eso saben bastante los hackers que visitan estos foros :)

keys() devuelve las claves del hash nunca en el mismo orden (por temas de seguridad). Entonces, no queda más remedio que escribir nuestro propio orden.

Si me ajusto a lo que pides, se puede solventar de esta manera:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %agentes = (                          # Definimos los agentes a identificar y cambiar
  2.     Android => 'Android',
  3.     Linux   => 'Linux',
  4.     Windows => 'Windows',
  5.     MSIE    => 'Windows',
  6. );
  7.                                          # definimos el orden que queremos
  8. my @agentes = ('Android', 'Linux', 'Windows');
  9. my $agentes = join "|", @agentes;        # construimos una expresión regular
  10. $agentes    = qr/\b($agentes)\b/;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

De todas maneras, esto es apaño.

Lo mejor sería definir una serie de prioridades, para saber cómo queremos interpretar la información del User-Agent.

En CPAN tienes el módulo Parse::HTTP::UserAgent, que puedes usar para "intentar" interpretar las cadenas del User-Agent. Digo "intentar", según los comentarios graciosos que aparecen en la misma página de este módulo :)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Anterior

Volver a Básico

¿Quién está conectado?

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