• Publicidad

Consulta sobre procesamiento 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.

Consulta sobre procesamiento de texto

Notapor koteo » 2010-02-18 07:03 @335

Ante todo disculparme, ya que no me he presentado antes. Estoy empezando Perl, sé programar algo de shell y lo básico en Ruby, y Perl, lo mínimo. Tengo que hacer un parser de logs específico, en el que necesito pasar lo que parseo a un csv.

1º Empezar a leer un fichero línea a línea.

2º Encontrar un timestamp y convertirlo a un formato más ameno y guardarlo en un array

3º Continuar hasta encontrar una línea que empiece por freeMemory.value y guardarlo en un array.

4º Continuar hasta encontrar una línea que empiece por totalMemory.value y guardarlo en un array.

5º Continuar leyendo y ver si puedo encontrar totalMemory.value o freeMemory.value antes de ver un timestamp; si no lo encuentro entonces, volver al punto 2.

6º Guardar la información en un csv.


Antes de nada, quiero decir que no pido que me hagan los deberes, pero sí una pequeña orientación en cómo hacerlo e incluso algún ejemplo que pueda ayudarme.

Ejemplo del texto a procesar:
http://pastebin.com/m3b01ddfc

El caso es que debo restar totalMemory.value - freeMemory.value (como podéis ver, entre timestamp y timestamp hay 4 líneas que hacen referencia a freeMemory y totalMemory (en el orden que lo digo). Encuentro freeMemory, encuentro totalMemory y hago la resta (totalMemory - freeMemory), ahora repito esto hasta encontrar el timestamp. En este fichero de log es así, pero si obtengo el log de otros servidores tienen 2 líneas solo entre timestamp y timestamp (1 de freeMemory y otra de totalMemory).

El csv quedaría algo similar a esto:

timestamp_personalizado;resultado_resta_OC4J1;resultado_resta_OC4J2 (si en el log hubiese 4 entradas)

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
23-02-2010 14:00;234000;220000
23-02-2010 14:05;223000;300000
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Espero haberme explicado.

Gracias.
koteo
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2010-02-16 17:14 @760

Publicidad

Re: Consulta sobre procesamiento de texto

Notapor explorer » 2010-02-18 08:45 @406

Bienvenido a los foros de Perl en Español, koteo.
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: Consulta sobre procesamiento de texto

Notapor explorer » 2010-02-18 13:11 @591

Esta es una posible solución. La salida no es exactamente como lo esperabas, pero bueno, no es cuestión de dar toda la solución :)

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use DateTime::Format::HTTP;
  7.  
  8. my @linea_salida;                                           # Guarda la información de una línea
  9.  
  10.  
  11. while (my $linea_entrada = <>) {                            # Para todas las líneas del fichero
  12.  
  13.     chomp $linea_entrada;                                   # Quitamos el carácter de fin de línea
  14.  
  15.     my @campos = split " ", $linea_entrada;                 # Dividimos la línea por los espacios en blanco
  16.  
  17.     if (@campos == 6) {                                     # Si hay 6 campos, suponemos que sí es una fecha
  18.  
  19.         my $fecha;
  20.  
  21.         eval {                                              # Intentamos interpretarla
  22.             $fecha
  23.                 = DateTime::Format::HTTP->parse_datetime($linea_entrada);
  24.         };
  25.  
  26.         if ($fecha) {                                       # Sí que es una fecha
  27.  
  28.             salida_linea();                                 # Sacamos la línea guardada antes
  29.  
  30.             @linea_salida                                   # Inicializamos la nueva línea de salida
  31.                 = $fecha->date() . ' ' . $fecha->time();
  32.         }
  33.     }
  34.  
  35.     # Ver si es un campo interesante
  36.     if ($campos[0]  and  $campos[0] =~ /(freeMemory|totalMemory)\.value/) {
  37.  
  38.         if ($1 eq 'freeMemory') {                               # Si es un freeMemory,
  39.             push @linea_salida, $campos[1];                     # lo guardamos
  40.         }
  41.         else {                                                  # Si es un totalMemory,
  42.             $linea_salida[-1] = $campos[1] - $linea_salida[-1]; # calculamos la diferencia
  43.         }
  44.     }
  45. }
  46.  
  47. salida_linea();                                             # Si queda alguna línea por salir
  48.  
  49.  
  50. sub salida_linea {                                          # Sacar una línea en pantalla
  51.     if (@linea_salida) {
  52.         print join(';', @linea_salida), "\n";               # Unimos los campos con ';'
  53.     }
  54. }
  55.  
  56. __END__
  57. 2010-01-30 16:20:01;337270;334603
  58. 2010-01-30 16:25:01;339659;337260
Coloreado en 0.003 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: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Consulta sobre procesamiento de texto

Notapor koteo » 2010-02-18 14:43 @654

¡¡ Muchas gracias !!

¡Voy a probar!
koteo
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2010-02-16 17:14 @760

Re: Consulta sobre procesamiento de texto

Notapor explorer » 2010-02-18 16:08 @714

Esta es otra variación, usando expresiones regulares.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use DateTime::Format::HTTP;
  7.  
  8. ## Definición de la gramática
  9. my $palabra   = qr/[\w:]+/;                                 # Una palabra
  10. my $timestamp = qr/(?:$palabra\s){6}/;                      # Un timestamp son 6 palabras
  11.  
  12. ## Leer el fichero
  13. my $log = do { undef $/; open F,'<m3b01ddfc.txt'; <F> };    # Leemos el log entero
  14.  
  15. ## Procesamos, mientras existan $timestamp
  16. while($log =~ /^ ($timestamp) (.*?) (?=$timestamp|\z)/simogx) {
  17.     my ($fecha, $resto) = ($1, $2);
  18.  
  19.     eval {                                                  # Intentamos interpretarla
  20.         $fecha
  21.             = DateTime::Format::HTTP->parse_datetime($fecha);
  22.     };
  23.  
  24.     next if not $fecha;                                     # No es una fecha, seguimos
  25.  
  26.     print $fecha->date() . ' ' . $fecha->time();            # Nuevo timestamp
  27.  
  28.                                                             # Valores de la memoria
  29.                                                             # que pueden repetirse varias veces
  30.     while ($resto =~ /freeMemory\.value: \s+ (\d+) .*? totalMemory\.value: \s+ (\d+)/simogx) {
  31.  
  32.         print ';' . ($2 - $1);
  33.     }
  34.  
  35.     print "\n";                                             # Fin de línea
  36. }
  37.  
  38. __END__
  39. 2010-01-30 16:20:01;337270;334603
  40. 2010-01-30 16:25:01;339659;337260
Coloreado en 0.002 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: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Consulta sobre procesamiento de texto

Notapor koteo » 2010-02-18 16:21 @723

Este último código me gusta mucho y funciona a la perfección, aunque este regexp, no lo entiendo muy bien:

$log =~ /^ ($timestamp) (.*?) (?=$timestamp|\z)/simogx)

Voy a leer un rato.
koteo
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2010-02-16 17:14 @760

Re: Consulta sobre procesamiento de texto

Notapor explorer » 2010-02-18 16:31 @730

En las líneas 9 y 10 definimos qué es un timestamp: un conjunto de 6 palabras, separados por espacios en blanco.

La expresión regular

$log =~ /^ ($timestamp) (.*?) (?=$timestamp|\z)/simogx

quiere decir:
* A lo largo de todo (/g) el $log, buscamos...

* Que al principio de la línea (^), buscamos un timestamp, y lo guardamos en $1 con la ayuda de los paréntesis de captura,

* seguido de "algo" (.*?) que guardaremos en $2,

* y seguido por, o bien, otro timestamp o (|) el final de todo el fichero (\z). Esto último no lo capturamos (?=), porque lo dejaremos para la siguiente vuelta.

Además, indicamos las siguientes opciones:
* /s - consideramos a $log como una gran cadena de caracteres
* /m - dentro de ella, hay caracteres de final de línea
* /i - nos da igual que sea mayúsculas o minúsculas
* /o - queremos que Perl solo haga una vez la interpretación de esta regex
* /x - para hacerla más clara la regex, nos permite separar con espacios los distintos campos de la regex
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: Consulta sobre procesamiento de texto

Notapor koteo » 2010-02-18 16:42 @737

Mil gracias de nuevo.

Ahora me toca intentar hacerlo a mi, aunque sea de otra manera.

Un saludo.
koteo
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2010-02-16 17:14 @760

Re: Consulta sobre procesamiento de texto

Notapor koteo » 2010-02-20 20:25 @892

Hola, estaba probando a hacerlo a "mi manera", pero creo que lo estoy complicando demasiado.

Lo que he intentado es: meter el timestamp en un array, freeMemory en otro y totalMemory en otro; luego unir freeMemory y totalMemory para así restarlo, pero la verdad que no sé cómo hacerlo, o bien antes de unirlo hacer la operación de restarlo. Sé que es más rebuscado de esta forma, pero no se me ocurrían más formas de hacerlo.

¿Qué opináis? La forma en la que estaba intentando hacerlo, ¿ se suele usar ?

Muchas gracias.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;                                                                                                                                
  2. use warnings;                                                                                                                              
  3.  
  4. # DEFINO LOS REGEXP
  5. my $timestmp = '\w+\s\w+\s\d+\s\d+\:\d+\:\d+\s\w+\s\d+';
  6.  
  7. # Descriptor de ficheros (Entrada y Salida)
  8. my $filenamein = "metrics.30.log";
  9. my $filenameout = "$filenamein.out";
  10.  
  11. #
  12. # Aquí declaramos los array
  13. my @timestamp;
  14. my @freem;
  15. my @totmem;
  16. #
  17. #my @resta = map { $totmem[1] - $freem[1] } ( 0 .. $#totmem );
  18. #
  19.  
  20. open (FILEIN, "<", $filenamein) || die "Problems: $!";
  21. #open (FILEOUT, "> $filenameout") || die "Problems: $!";
  22.  
  23. while (<FILEIN>) {
  24.     if ($_ =~ /^$timestmp/){
  25.         push @timestamp, [ split ];
  26.     }
  27.     elsif ($_ =~ /^freeMemory\.value:\s+(\d+)/) {
  28.         push @freem, [ split ];
  29.     }
  30.     elsif ($_ =~ /^totalMemory.value/) {
  31.         push @totmem, [ split ];
  32.     }
  33.  
  34. }
  35.  
  36.  
  37. my @res = sort(@freem,@totmem);
  38.  
  39. foreach(@res) {
  40.     print "@$_[1]\n";
  41. }
  42.  
  43. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
koteo
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2010-02-16 17:14 @760

Re: Consulta sobre procesamiento de texto

Notapor explorer » 2010-02-20 21:38 @943

Hay un problema si se hace de esta manera: según los requerimientos, pueden aparecer más de una vez la pareja freeMemory y totalMemory, con lo que al final del bucle tienes un número distinto de elementos de estos arreglos con respecto al arreglo de timestamp.

Lo podrías solventar usando alguna especie de bandera, que indique que acabas de leer un timestamp y que entonces, los pares de parejas de valores que has leído antes les puedes procesar.

Así es como funciona mi primera solución, solo que en vez de tres arreglos uso solo uno (por abreviar, pero es lo mismo que si tuviera tres). Uso solamente uno porque en realidad está guardando ya la salida: primero el timestamp y luego parejas de valores, de los que primero guardo el freeMemory y luego lo reemplazo por la diferencia entre el totalMemory y el valor almacenado antes.

Bueno... son trucos para usar la menor cantidad posible de variables y memoria, pero que en ocasiones hacen el código más difícil de leer.

Lo que no entiendo es el uso de sort(), que haces en la línea 37.

En caso de duda, usa el módulo Data::Dumper, para ver el contenido de una variable.
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

Siguiente

Volver a Básico

¿Quién está conectado?

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