• Publicidad

Comparar 2 archivos en 2 campos

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

Comparar 2 archivos en 2 campos

Notapor Erick2186 » 2012-06-05 13:18 @596

Buenas tardes, desde México.

Tengo una duda tal vez muy básica... lo que quiero hacer es poder comparar dos archivos con el primer archivo [campo1]~[campo2]~[campo3]~...~[campon],

y el segundo archivo [campo1]~[campo2]~[campo3]~...~[campon]

El separador es '~'.

Al estar buscando en el foro encontré el siguiente código:

#!/usr/bin/perl
use common::sense; # sentido común
use autodie; # y sacrificio
use File::Slurp; # sin dejar de chupar
## Leer ficheros
my @primer_archivo = read_file('Nuevo.txt');
my @segundo_archivo = read_file('Viejo.txt');

## Transformación del segundo archivo
for my $linea (@segundo_archivo) {
$linea = (split " ", $linea)[0]; # Nos quedamos solo con
# la primera cadena de cada línea
}
## Apertura del fichero de diferencias
open my $fichero_diferencias, '>', 'Diferencias.txt';
## Comparación
for my $linea (@primer_archivo) {
my $primera_cadena = (split " ", $linea)[0];
unless ($primera_cadena ~~ @segundo_archivo) { # a menos que la $primera_cadena esté en el @segundo_archivo,
print $fichero_diferencias $linea; # lo escribimos en el $fichero_diferencias
}
}
## Cierre del fichero de diferencias
close $fichero_diferencias;
__END__

Me "sirvió" pero tarda mucho debido a la cantidad de información en la línea que se maneja, aparte no me "sirve" para lo que necesito debido a que los campos que necesito que sean idénticos serían el [campo1] del primer archivo con el [campo1] del segundo archivo y el [campo3] del primer archivo con el [campo3] del segundo archivo y no toda la línea.

Aparte quisiera que se generara un tercer archivo con toda la línea.

De antemano, les agradezco su ayuda.
Erick2186
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2012-06-01 14:57 @665

Publicidad

Re: Comparar 2 archivos en 2 campos

Notapor MARKO » 2012-06-05 16:41 @736

En una oportunidad anterior, explorer me aconsejó que se ahorra mucho tiempo eliminando la combinación split()/for() para las búsquedas convirtiendo tu archivo en una estructura bidimensional.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. @vector = map { [ split /~/, $_ ] } @vector;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Con la línea anterior creaste un vector el cual cada elemento es una referencia de otro arreglo que contiene cada una de las columnas.

Y luego para hacer referencia a cada uno de los campos lo haces de la manera siguiente:

Primero indicas qué línea y luego qué columna quieres. Supongamos que quieres la línea 5 y la columna 3.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $variable = $vector [5][3] # en $variable quedará el valor de la tercera columna de la quinta fila
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Solo quedaría que hicieras un recorrido por todo tu archivo y que compararas las columnas que tu quieres y realizaras los procesos que necesitas cada vez que sean iguales.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. OPEN (NUEVO,nuevo.txt) or die
  2. OPEN (VIEJO,viejo.txt) or die
  3.  
  4. my @vectornuevo = <NUEVO>;
  5. @vectornuevo = map { [ split /~/, $_ ] } @vectornuevo;
  6. my $longitud = scalar (@vectornuevo);
  7.  
  8. my @vectorviejo = <VIEJO>;
  9. @vectorviejo = map {[split /~/,$_]} @vectorviejo;
  10.  
  11. my $indice=0;
  12.  
  13. while ($indice<$longitud){
  14.    if ($vectornuevo[$indice][1]==$vectorviejo[$indice][1]){
  15.       #proceso si el [campo 1] del primer archivo es igual al [campo 1] del otro archivo
  16.    }
  17.    
  18.    if ($vectornuevo[$indice][3]==$vectorviejo[$indice][3]){
  19.       #proceso si el [campo 3] del primer archivo es igual al [campo 3] del otro archivo
  20.    }
  21.  
  22.    $indice++;
  23. }
  24.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Éxitos.
MARKO
Perlero nuevo
Perlero nuevo
 
Mensajes: 86
Registrado: 2012-01-10 22:34 @982

Re: Comparar 2 archivos en 2 campos

Notapor explorer » 2012-06-05 18:06 @795

Lo que no sabemos es qué línea, de los archivos, es la que quiere grabar.

Supongamos que es la del segundo archivo.

Esta es otra solución, basada en hash.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.12;
  3. use autodie;
  4.  
  5. open my $ARCHIVO1, '<', 'archivo1';
  6. open my $ARCHIVO2, '<', 'archivo2';
  7. open my $ARCHIVO3, '>', 'archivo3';
  8.  
  9. # 1- Leemos el primer archivo, almacenando la información en el hash
  10. my %archivo1;
  11.  
  12. while (my $linea = <$ARCHIVO1>) {
  13.     chomp $linea;
  14.  
  15.     my($campo1, undef, $campo3) = split /~/, $linea, 4;
  16.  
  17.     $archivo1{"$campo1~$campo3"} = 1;
  18. }
  19.  
  20. # 2- Leemos el segundo archivo, comparando y grabando
  21. while (my $linea = <$ARCHIVO2>) {
  22.     chomp $linea;
  23.  
  24.     my($campo1, undef, $campo3) = split /~/, $linea, 4;
  25.  
  26.     if ($archivo1{"$campo1~$campo3"}) {
  27.  
  28.         say $ARCHIVO3 $linea;
  29.     }
  30. }
  31.  
  32. close $ARCHIVO1;
  33. close $ARCHIVO2;
  34. close $ARCHIVO3;
  35.  
  36. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Lo que hacemos es, para el primer archivo, almacenar la información de los campos como claves de un hash. Luego, recorremos las líneas del segundo archivo, sacar sus campos, y si estos forman una de las claves que ya teníamos, pues es que hay coincidencia, así que grabamos la $linea en el $ARCHIVO3.

Mejora de velocidad: si sabemos que los archivos siempre van a tener más de 3 campos, podemos quitar los chomp() y cambiar el say() por un print() (porque no es necesario quitar caracteres de fin de línea para luego ponerlos).
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: Comparar 2 archivos en 2 campos

Notapor Erick2186 » 2012-06-06 00:54 @079

Muchísimas gracias a los dos por su pronta respuesta. Me sirvió de mucho. Ya solo le modifiqué lo que necesitaba por que era la diferencia, con un símbolo de diferente a "!".

Ahora a seguir profundizando en este lenguaje y con "maestros" como ustedes que resuelven las dudas muy bien explicadas y elaboradas. Uno se siente a gusto de preguntar...

GRACIAS
Erick2186
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2012-06-01 14:57 @665

Re: Comparar 2 archivos en 2 campos

Notapor Erick2186 » 2012-06-12 13:00 @583

Disculpen la molestia, pero me surgió una duda.

my($campo1, undef, $campo3) = split /~/, $linea, 4;

¿Por qué o para qué sirve el 4, o qué indica?
Erick2186
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2012-06-01 14:57 @665

Re: Comparar 2 archivos en 2 campos

Notapor explorer » 2012-06-12 15:53 @703

Indica el número de veces que split() debe "partir" la línea.

Con '4', indicamos que queremos que solo parta la línea en 4 partes, de las que las 3 primeras irán a parar al lado izquierdo de la asignación.

Más información en perldoc -f split.
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: Comparar 2 archivos en 2 campos

Notapor Erick2186 » 2012-06-13 23:35 @024

Ooook... Muchíiisimas gracias... todo quedó más claro... Gracias, explorer.
Erick2186
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2012-06-01 14:57 @665


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: Google [Bot] y 0 invitados

cron