• Publicidad

Búsqueda de cadenas en un archivo

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

Búsqueda de cadenas en un archivo

Notapor titantux » 2013-01-31 14:46 @657

Hola, ¿qué tal? Un saludos a todos.

Tengo un problema de búsqueda de cadenas con expresiones regulares que no he podido resolver.

Mi problema es el siguiente:

Archivo A:

130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0



Por cada línea junto las columnas en rojo para que me quede así:

52831114916620130111000008 => 831114916620130111000008

Y después buscarla en el archivo siguiente:

Archivo B:

8311149166|8311149166|||1|4|11583111491662013011100000801|2013-01-11 00:08:54|2013-01-11 00:00:08|
9171134738|9171134738|||1|8|11591711347382013011100001101|2013-01-11 00:08:54|2013-01-11 00:00:11|
3334985134|3334985134|||1|5|11533349851342013011100000401|2013-01-11 00:08:54|2013-01-11 00:00:04|
6981101359|6981101359|||1|2|11569811013592013011100000801|2013-01-11 00:08:54|2013-01-11 00:00:08|
6531342313|6531342313|||1|1|11565313423132013011100000901|2013-01-11 00:08:54|2013-01-11 00:00:09|


Resultado esperado:


SI MATCH -> 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0



Lo que me sale con este código:

NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0
NO MATCH -> 443410446020130111000014 ** 130111000014; 0; 1294; 3; 2; 524434104460; 20986; 524434104460; 20986; 2; 0; 0
NO MATCH -> 831114916620130111000008 ** 130111000008; 0; 1298; 3; 2; 528311149166; 20986; 528311149166; 20986; 2; 0; 0
NO MATCH -> 662101154720130111000015 ** 130111000015; 0; 1298; 3; 2; 526621011547; 20986; 526621011547; 20986; 2; 0; 0
NO MATCH -> 713114789220130111000018 ** 130111000018; 0; 1294; 3; 2; 527131147892; 20987; 527131147892; 20987; 2; 0; 0
NO MATCH -> 642109609420130111000008 ** 130111000008; 0; 1294; 3; 2; 526421096094; 20986; 526421096094; 20986; 2; 0; 0



¿ Alguien me puede dar una pequeña ayuda ?

¡¡¡Saludos y Gracias!!!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use diagnostics;
  3. use strict;
  4.  
  5. my %storecall = ();
  6. open my $IN1, '<', $ARGV[0] or die "Unable to open input file: $!\n";
  7. open my $IN2, '<', $ARGV[1] or die "Unable to open input file: $!\n";
  8.  
  9. while ( my $linea = <$IN1> ) {
  10.     my (@columna) = split( ";", $linea );
  11.     my $_ = $columna[5] . "20" . $columna[0];
  12.     s/\d{2}//;
  13.     my $calldetail = $_;
  14.     $storecall{$calldetail} = $linea;
  15. }
  16.  
  17. while ( my $line2 = <$IN2> ) {
  18.     foreach my $clave ( keys %storecall ) {
  19.  
  20.         if ( $line2 =~ /$clave/ ) {
  21.             print "SI MATCH -> $clave  ** $storecall{$clave}";
  22.         }
  23.         else {
  24.             print "NO MATCH -> $clave  ** $storecall{$clave}";
  25.         }
  26.     }
  27. }
  28.  
  29. close($IN1);
  30. close($IN2);
  31.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2013-01-31 14:57 @665, editado 1 vez en total
Razón: Formateado de código con Perltidy
titantux
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-01-31 14:02 @626
Ubicación: Mexico, D.F.

Publicidad

Re: Búsqueda de cadenas en un archivo

Notapor explorer » 2013-01-31 15:32 @689

Bienvenido a los foros de Perl en Español, titantux.

El primer problema está en el split(). Estás partiendo por el delimitador ';', pero vemos en el mensaje que las líneas contienen espacios en blanco alrededor de ese delimitador. La consecuencia es que las claves que estás guardando contienen un espacio en blanco delante:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
[ 831114916620130111000008]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Así que hay que quitarlos...

Otro detalle está en el modo de búsqueda... Parece que quieres saber si el código está en las líneas del segundo archivo, y no al revés, así que hay que hacer los bucles de las búsquedas al revés.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. my %storecall = ();
  7. open my $IN1, '<', $ARGV[0] or die "Unable to open input file: $!\n";
  8. open my $IN2, '<', $ARGV[1] or die "Unable to open input file: $!\n";
  9.  
  10. while ( my $linea = <$IN1> ) {
  11.     my @columna    = split( /\s*;\s*/, $linea );
  12.     my $calldetail = $columna[5] . '20' . $columna[0];
  13.     $calldetail    =~ s/^\d{2}//;
  14.     $storecall{$calldetail} = $linea;
  15. }
  16.  
  17. my @B = <$IN2>;
  18.  
  19. close($IN1);
  20. close($IN2);
  21.  
  22. my $encontrado;
  23.  
  24. for my $clave ( sort keys %storecall ) {
  25.     $encontrado = 0;
  26.  
  27.     for my $line2 (@B) {
  28.         if ( $line2 =~ /$clave/ ) {
  29.             $encontrado = 1;         # encontrado
  30.             last;                    # no hace falta seguir buscando más
  31.         }
  32.     }
  33.  
  34.     if ($encontrado) {
  35.         print "SI";
  36.     }
  37.     else {
  38.         print "NO";
  39.     }
  40.     print " MATCH -> $clave  ** $storecall{$clave}";
  41. }
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

Re: Búsqueda de cadenas en un archivo

Notapor titantux » 2013-01-31 16:15 @718

¡¡¡Wow!!! ¡¡Qué respuesta tan rápida!! :shock:

¡¡Realmente fue un detalle fino esto!! :roll:

Gracias, me pasé leyendo varias horas el manual y jamás se me ocurrió que el detalle eran los espacios. :lol:
titantux
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-01-31 14:02 @626
Ubicación: Mexico, D.F.

Re: Búsqueda de cadenas en un archivo

Notapor explorer » 2013-01-31 19:28 @853

La siguiente versión es más compacta, y se deja como ejercicio para el lector :)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4.  
  5. my %storecall;
  6.  
  7. open my $IN1, '<', shift;
  8. open my $IN2, '<', shift;
  9.  
  10. while (<$IN1>) {
  11.     chomp;
  12.     my @c = split /;\s*/;
  13.     $storecall{ substr($c[5], 2) . "20$c[0]" } = $_;
  14. }
  15.  
  16. my @B = <$IN2>;
  17.  
  18. close $IN1;
  19. close $IN2;
  20.  
  21. say +(/$_/ ~~ @B ? 'SI' : 'NO') . " MATCH -> $_  ** $storecall{$_}" for sort keys %storecall;
  22.  
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

Re: Búsqueda de cadenas en un archivo

Notapor titantux » 2013-02-01 08:09 @381

Una pregunta más...
¿Qué pasa si lo quiero para archivos muy grandes?

Digamos que ambos archivos tienen dos millones de líneas. Se torna un poco lento.

¿Hay alguna manera de hacerlo más rápido?

Mi idea principal fue usar el hash para meterlo a memoria y manejarlo así,
pero entonces, ¿ es una cuestión de hardware ?


Esté ultimo ejemplo, pareciera que corre más rápido, pero... me da un: "core dump". :(
Tengo 4Gb de memoria RAM.
titantux
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-01-31 14:02 @626
Ubicación: Mexico, D.F.

Re: Búsqueda de cadenas en un archivo

Notapor explorer » 2013-02-01 18:52 @828

¿No estarás usando Windows, verdad?

Con 4Gb hay espacio de sobra para esos cuatro millones de líneas...

Otra opción: en lugar de leer todo el archivo en @B, como un array, lo leemos con un escalar (todo el archivo en una única variable), y hacemos el proceso de buscar las claves dentro de ese montón:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. my %storecall = ();
  7. open my $IN1, '<', $ARGV[0] or die "Unable to open input file: $!\n";
  8. open my $IN2, '<', $ARGV[1] or die "Unable to open input file: $!\n";
  9.  
  10. while ( my $linea = <$IN1> ) {
  11.     my @columna    = split( /\s*;\s*/, $linea );
  12.     my $calldetail = $columna[5] . '20' . $columna[0];
  13.     $calldetail    =~ s/^\d{2}//;
  14.     $storecall{$calldetail} = $linea;
  15. }
  16.  
  17. undef $/;   # modo "aspiradora"
  18. my $B = <$IN2>;
  19.  
  20. close($IN1);
  21. close($IN2);
  22.  
  23. for my $clave ( sort keys %storecall ) {
  24.  
  25.     if ( $B =~ /$clave/ ) {
  26.         print "SI";
  27.     }
  28.     else {
  29.         print "NO";
  30.     }
  31.     print " MATCH -> $clave  ** $storecall{$clave}";
  32. }
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

Re: Búsqueda de cadenas en un archivo

Notapor titantux » 2013-02-02 02:06 @129

¡¡¡Nop!!!, uso Ubuntu 12.10 64 bits & 3.5.0-21-generic.

Voy a probarlo de esa forma en escalar.

Se me había ocurrido también intentarlo en forma paralela es decir, tomar las primeras 10 claves, hacer la búsqueda, imprimir resultado, siguientes 10, etc...


Sintáxis: [ Descargar ] [ Ocultar ]
  1.  use subs::parallel; 
  2.  
  3.  my $foo = parallelize { 
  4.   # do stuff here 
  5.  }; 
  6.  
  7.  my $bar = parallelize { 
  8.   # do even more stuff 
  9.  }; 
  10.  
  11.  # now we wait for them to finish 
  12.  print "$foo, $bar\n"; 


Pero estoy ahora viendo cómo solucionar y sacarlas primeras 10 llaves del hash, para poder usar la estructura de bloques en paralelo.

En fin, primero lo intento como escalar y veo que pasa, después comento mis resultados.

¡Gracias!
titantux
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-01-31 14:02 @626
Ubicación: Mexico, D.F.

Re: Búsqueda de cadenas en un archivo

Notapor explorer » 2013-02-02 08:59 @416

Pues... tienes razón: no es necesario leer todas las claves a buscar.

Así, se puede reducir el programa aún más: ya no necesitamos el hash.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5. use autodie;
  6.  
  7. my $B;
  8. {
  9.     local $/;           # modo "aspiradora". Localizamos la var. para que no afecte a $IN1
  10.  
  11.     open my $IN2, '<', $ARGV[1];
  12.     $B = <$IN2>;
  13.     close $IN2;
  14. }
  15.  
  16. open my $IN1, '<', $ARGV[0];
  17.  
  18. while (my $linea = <$IN1>) {
  19.     my @columna    = split /;\s*/, $linea, 7;           # solo necesitamos partir en 7 partes
  20.     my $calldetail = $columna[5] . '20' . $columna[0];
  21.     $calldetail    = substr $calldetail, 2;
  22.  
  23.     if ( $B =~ /$calldetail/ ) {
  24.         print "SI MATCH -> $calldetail  ** $linea";
  25.     }
  26.     else {
  27.         print "NO MATCH -> $calldetail  ** $linea";
  28.     }
  29. }
  30.  
  31. close($IN1);
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

Re: Búsqueda de cadenas en un archivo

Notapor titantux » 2013-02-02 21:35 @941

He aquí unas pruebas que he hecho:

Archivo a: 1 369 líneas
Archivo b: 2 384 373 líneas

Versión 3 sin hash
real 4m36.795s
user 4m35.409s
sys 0m0.508s

Versión 2 con escalar y hash
real 4m36.610s
user 4m35.245s
sys 0m0.512s

Versión 1 y hash

real 12m54.022s
user 12m48.884s
sys 0m0.896s

Ahora estoy probando con un archivo "a" de 1 850 000 líneas; el "b" sí es de 2 400 000 líneas.
titantux
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2013-01-31 14:02 @626
Ubicación: Mexico, D.F.

Re: Búsqueda de cadenas en un archivo

Notapor explorer » 2013-02-02 22:05 @962

Se ve claro que todo el tiempo se pierde en la expresión regular.

Como se trata de un patrón de búsqueda en la que no hay comodines ni anclas, podemos cambiarla por una búsqueda con la función index(): cambias
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ( $B =~ /$calldetail/ ) {
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
por
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ( -1 != index $B, $calldetail ) {
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Pero también sería interesante saber más cosas. Por ejemplo, ¿las claves que extraemos del archivo "a" pueden repetirse o son únicas? ¿Las claves pueden encontrarse en "b" solo una vez o varias veces?
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: Bing [Bot] y 1 invitado

cron