• Publicidad

Buscar dato en archivo

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

Buscar dato en archivo

Notapor lis » 2013-07-23 11:12 @508

Hola, amigos del foro.

Tengo un archivo que que tiene 5 columnas, la primera corresponde a fecha y hora juntos -AAAAMMDDHH- (por ejemplo, 2012010100) pero falta un día (es el año 2012 completo) e hice un script para que buscara esa fecha, y es obvio que estoy haciendo algo mal porque el resultado muestra una fecha, pero al revisar el archivo esa fecha sí está.

Agradezco mucho si me ayudan. Adjunto mi script:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. open(DATA,"<WRF_HUARA.txt");
  4.  
  5. %hash = qw (01 31 02 29 03 31 04 30 05 31 06 30 07 31 08 31 09 30 10 31 11 30 12 31);
  6. foreach my $mes (sort keys %hash){
  7. foreach my $dia ( '01' .. "$hash{$mes}" ) {
  8. foreach my $hora ('00' .. '23'){
  9.  
  10. $fecha='2012' . $mes . $dia . $hora;
  11.  
  12. while($lineas=<DATA>){
  13. chop($lineas);
  14. @datos= split(" ",$lineas);
  15.  
  16. if ($datos[0] =~ m/$fecha/){
  17.  
  18. print "$fecha se encuentra en $datos[0]\n";
  19. }else{
  20. print"$fecha no se encuentra en $datos[0]\n";
  21. }
  22.  
  23. }}}}
  24.  
  25. close(DATA);
  26.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
lis
Perlero nuevo
Perlero nuevo
 
Mensajes: 106
Registrado: 2008-05-27 21:43 @946

Publicidad

Re: Buscar dato en archivo

Notapor explorer » 2013-07-23 11:18 @512

Y las fechas que están dentro del archivo, ¿en qué orden están? ¿En el natural, o desordenadas, u otro orden?
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: Buscar dato en archivo

Notapor lis » 2013-07-23 11:25 @517

Hola, explorer.
Están en este orden:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
2012010100      19      66      4.48     277.95
2012010101      19      68      3.74     298.48
2012010102      19      68      3.08     275.45
2012010103      18      68      4.02     290.57
2012010104      18      70      2.73     285.49
2012010105      17      87      0.15     153.46
2012010106      17      89      1.28     238.21
2012010107      17      92      1.24     279.74
2012010108      16      89      1.32     269.44
2012010109      16      83      1.63     286.37
2012010110      17      79      3.45     284.84
2012010111      19      72      3.69     285.70
2012010112      21      63      4.82     292.99
2012010113      23      56      4.34     298.23
2012010114      24      53      3.69     306.36
2012010115      25      49      3.85     304.29
2012010116      26      49      5.03     295.78
2012010117      27      49      5.62     295.08
2012010118      27      50      6.59     292.61
2012010119      26      51      7.08     287.49
2012010120      26      53      6.65     284.43
2012010121      25      55      6.28     284.18
2012010122      23      59      5.66     288.06
2012010123      22      62      5.10     299.44
2012010200      21      65      5.83     314.83
2012010201      20      69      4.73     319.92
.               .        .       .        .
.               .        .       .        .
.               .        .       .        .
2012123123      21      58      4.36     305.15
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
lis
Perlero nuevo
Perlero nuevo
 
Mensajes: 106
Registrado: 2008-05-27 21:43 @946

Re: Buscar dato en archivo

Notapor explorer » 2013-07-23 11:35 @524

Hay dos problemas:
  • la comparación la haces con una expresión regular, pero es mejor que lo hagas con un operador de comparación de cadenas de caracteres: 'eq'
  • el problema gordo está en el algoritmo. Tienes un triple bucle for() para recorrer todas las fechas. Por cada una de ellas, tu intención es leer las fechas del archivo, y buscar la coincidencia. El problema, bueno, varios problemas, son:
    • imprimes un mensaje de está o no está por cada fecha existente en el archivo. Eso quiere decir que, en la primera fecha, 2012010100, saldrá un mensaje de que sí está (está en la primera línea del archivo), seguido de 366*24 mensajes de que "no está", porque, efectivamente, el resto de fechas del archivo ya no coincide con la primera
    • una vez terminado de leer el archivo, el triple bucle sigue, pero... ¡el archivo ya se agotó de leer! Deberías abrir y cerrar el archivo dentro del triple bucle. O mejor aún: hacer un seek() para colocar el puntero de lectura al principio.
Lo malo... es que la ejecución del programa se va a hacer eterno... (366x24)^2 = 77 158 656 vueltas.

Se inicia un concurso... a ver quién da con la solución más rápida...
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: Buscar dato en archivo

Notapor explorer » 2013-07-23 12:56 @580

Más preguntas.

¿Esa fecha/hora, a qué zona horaria se refiere? ¿Es hora local o GMT? Quiero decir que no me importa la zona horaria, sino si es hora local, ya que sabemos que hay dos momentos a lo largo del año (al menos aquí en España), donde la hora local cambia (pasa de horario de verano a invierno, y viceversa).

Si es hora local, entonces, en el archivo, puede aparecer líneas con fechas duplicadas (retrasar una hora) o con una línea de menos (adelantar una hora).

Si es GMT, entonces consideramos que todos los días tienen 24 horas. Y que puede haber un día bisiesto en febrero.
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: Buscar dato en archivo

Notapor lis » 2013-07-23 13:52 @619

Está en GMT.
lis
Perlero nuevo
Perlero nuevo
 
Mensajes: 106
Registrado: 2008-05-27 21:43 @946

Re: Buscar dato en archivo

Notapor explorer » 2013-07-23 17:48 @783

Esta es mi solución.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.16;
  3. use autodie;                    # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  4. use utf8::all;                  # Turn on UTF-8. All of it.
  5.  
  6. ## Configuración
  7. my $año = 2012;
  8. ## Fin de configuración
  9.  
  10. ## Constantes
  11. my %meses_días = (
  12.     '01' => '31',
  13.     '02' => '28',
  14.     '03' => '31',
  15.     '04' => '30',
  16.     '05' => '31',
  17.     '06' => '30',
  18.     '07' => '31',
  19.     '08' => '31',
  20.     '09' => '30',
  21.     '10' => '31',
  22.     '11' => '30',
  23.     '12' => '31',
  24. );
  25. if ($año % 4 == 0 and ($año % 100 != 0  or  $año % 400 == 0)) {
  26.     $meses_días{'02'} = '29';                                  # Este año es bisiesto
  27. }
  28.  
  29.  
  30. ## Variables
  31. my %fechas_en_archivo;
  32.  
  33. ## Leemos el archivo y nos quedamos solo con las fechas
  34. open my $WRF, 'WRF_HUARA.txt';
  35. while (<$WRF>) {
  36.     $fechas_en_archivo{ (split " ")[0] }++;
  37. }
  38. close   $WRF;
  39.  
  40. ## Recorremos todo el año
  41. for my $mes  ('01' .. '12'             ) {
  42. for my $día  ('01' .. $meses_días{$mes}) {
  43. for my $hora ('00' .. '23'             ) {
  44.  
  45.     my $fecha = "$año$mes$día$hora";
  46.  
  47.     if (exists $fechas_en_archivo{ $fecha }) {
  48.         delete $fechas_en_archivo{ $fecha };                    # Vamos borrando las fechas que vamos encontrando
  49.     }
  50.     else {                                                      # Hemos encontrado una fecha que no está en el archivo
  51.         say "Fecha $fecha no aparece en el archivo";
  52.     }
  53. }}}
  54.  
  55. ## Recorremos las fechas que aparecen demás en el archivo
  56. for my $fecha (sort keys %fechas_en_archivo) {
  57.     say "Fecha $fecha aparece demás en el archivo";
  58. }
  59.  
  60. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Bueno, yo he usado "features" de las nuevas versiones de Perl, pero debería serte fácil adaptar esta solución a tu problema.

Básicamente, consiste en leer primero todas las fechas del archivo, y luego, en el triple bucle, irlas borrando del hash. Si una fecha no estaba en el hash del archivo, tenemos una fecha que no aparece en el archivo. Y al final, un bucle más para identificar las fechas que sobran en el archivo (no corresponden con ninguna fecha normal esperada para ese año).
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: Buscar dato en archivo

Notapor lis » 2013-07-24 13:44 @614

Hola, explorer, tuve que instalar varios módulos y actualizar otros pero funcionó excelente. Muchísimas gracias una vez más.
lis
Perlero nuevo
Perlero nuevo
 
Mensajes: 106
Registrado: 2008-05-27 21:43 @946

Re: Buscar dato en archivo

Notapor otronovato » 2013-08-28 06:13 @301

He hecho un código que, a falta de un archivo de datos, no sé si funcionaría.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. my @fechas;
  7.  
  8. #Como hay un registro por hora por cada día, sabemos que tendremos
  9. #para enero 31 días * 24 horas = 744 registros
  10. #para febrero de 2012 29 días * 24 horas = 696 registros
  11. #para abril 30 días * 24 horas = 720 registros...
  12.  
  13. my %registros = (
  14.     "01" => 744,
  15.     "02" => 696,
  16.     "03" => 744,
  17.     "04" => 720,
  18.     "05" => 744,
  19.     "06" => 720,
  20.     "07" => 744,
  21.     "08" => 744,
  22.     "09" => 720,
  23.     "10" => 744,
  24.     "11" => 720,
  25.     "12" => 744
  26. );
  27.  
  28. my $contador;
  29. my @regpormes;
  30. my $incompleto;
  31. my @dias;
  32.  
  33. open( FH, "<", $ARGV[0] ) || die "No puedo abrir $ARGV[0]";
  34.  
  35. while (<FH>) {
  36.     chomp $_;
  37.     my @registro = split /\s+/, $_;
  38.     push @fechas, $registro[0];
  39. }
  40.  
  41. close FH;
  42.  
  43. #Compruebo que me he quedado con los datos que quiero
  44.  
  45. foreach (@fechas) {
  46.     print $_, "\n\n\n\n";
  47. }
  48.  
  49. #Primero localizamos el mes que está incompleto
  50.  
  51. foreach (@fechas) {
  52.  
  53.     $contador = 0;
  54.     foreach ( sort keys %registros ) {
  55.         if ( ~/\d\d\d\d$_.*/ ) {
  56.             $contador++;
  57.         }
  58.  
  59.         if ( $registros{$_} > $contador ) {
  60.             $incompleto = $_;
  61.         }
  62.     }
  63. }
  64. print "mes $incompleto\n";
  65.  
  66. #Luego encontramos el día que falta. Supondré que sólo hay uno
  67. foreach (@fechas) {
  68.  
  69.     if ( ~/\d\d\d\d$incompleto(\d\d).*/ ) {
  70.         push @dias, $1;
  71.     }
  72.  
  73. }
  74.  
  75. #quitamos todos los elementos repetidos mediante un hash
  76.  
  77. my %unicos = map { $_, 1 } @dias;
  78.  
  79. my @lista = sort keys %unicos;
  80.  
  81. print @lista, "\n\n";
  82.  
  83. #En la lista podríamos ver fácilmente el día que falta
  84.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


He supuesto que no tenemos problemas de cambios horarios y demás peculiaridades. De las expresiones regulares no estoy nada seguro, pues hace años que no las tocaba. ¿Podría haber extraído los campos mediante unpack()?... ¿Qué os parece? ¿Podría funcionar?

Me gustaría que me explicaseis esta línea de código de la solución de explorer:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $fechas_en_archivo{ (split " ")[0] }++;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Entiendo lo que hace, pero sólo porque imagino lo que debe hacer :shock:
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Buscar dato en archivo

Notapor explorer » 2013-08-28 08:00 @375

No he comprobado el programa pero, de funcionar, irá bastante más lento que mi solución: solo el hecho de no usar hash, y en su lugar usar bucles, para hacer las búsquedas, hará que el procesamiento se alargue muchísimo.

Precisamente, los hash son muy indicados para estos casos, en los que tenemos que saber si cierta información existe o ya ha salido antes.

La línea

$fechas_en_archivo{ (split " ")[0] }++;

hace lo siguiente:
  • split() parte la línea por los espacios en blanco. Devuelve una lista de elementos (los distintos campos encontrados)
  • de esa lista (que está rodeada por los paréntesis), nos quedamos sólo con el primer elemento ([0])
  • ese elemento se convierte en una clave dentro del hash %fechas_en_archivo, y como valor, el que teníamos antes, más uno
Es decir, vamos contando las veces que va apareciendo el valor que está en la primera columna. En la mayor parte de los casos (o todos), ese valor será un '1', pero eso no nos importa. Lo que nos importa es que hemos creado una clave con el valor de la primera columna. Eso nos servirá luego para saber si tal fecha la hemos leído antes o no (con un simple if(), no con un bucle).
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 21 invitados