• Publicidad

Buscar coincidencias en fichero

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

Buscar coincidencias en fichero

Notapor newperlero » 2011-07-15 06:51 @327

Hola, soy nuevo con Perl, y por más que intento hacer una cosa no lo consigo:
Tengo un fichero de texto, que contiene:

linea1
linea2
linea3
linea4
linea5

Por otra parte, tengo un fichero de texto que tiene la misma estructura, pero puede ser o no, que las líneas sean idénticas, por ejemplo, podría ser:

linea1
linea2
linea5555
linea1234

Necesito comparar los ficheros, y si en el fichero 2 existe "linea1", tengo que imprimir en otro fichero #linea1
Si no existe, tengo que imprimir la línea tal cual, o sea, linea1.

¿Podéis orientarme sobre cómo puedo hacer esto? Es un problema del algoritmo, que no doy con el correcto, y se me hace extraño que con Perl no pueda hacer algo con expresiones regulares para apañar este follón. ¿No hay alguna forma más sencilla para hacer esto?

He intentado hacer cosas como esta, sin éxito:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. while ( $line = <FICHERO1> ) {
  2.     while ( $line2 = <FICHERO2> ) {
  3.         if ( $line eq $line2 ) {
  4.             print FICHERO3 "#$line";
  5.             else { print FICHERO3 "$line" }
  6.         }
  7.     }
  8.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2011-07-15 07:12 @342, editado 1 vez en total
Razón: Formateado de código con Perltidy
newperlero
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2011-07-15 06:38 @318

Publicidad

Re: Buscar coincidencias en fichero

Notapor pvaldes » 2011-07-15 07:05 @337

abro fichero 1 para lectura
abro fichero 2 para lectura
para cada linea del fichero 1
para cada linea del fichero 2
si linea1 = linea2
print linea
else "hacer otra cosa"
cierro fichero 1
cierro fichero 2

O sea que la estructura que tienes es correcta pero el problema está en la línea 4, de entrada te falta un } tras la parte de print para cerrar el if y además es probable que tengas que escapar el símbolo # para que lo tome de manera literal (\#)

un posible enfoque más rápido probablemente sería usar next

"si no son iguales pasa a la siguiente, si son iguales sal del bucle e imprime (y olvida el resto del archivo)"
Última edición por pvaldes el 2011-07-15 07:12 @342, editado 1 vez en total
pvaldes
Perlero nuevo
Perlero nuevo
 
Mensajes: 129
Registrado: 2011-01-22 12:56 @580

Re: Buscar coincidencias en fichero

Notapor explorer » 2011-07-15 07:11 @341

Bienvenido a los foros de Perl en español, newperlero.

El problema del bucle que estás mostrando, es que, después de que FICHERO2 se agota (se lee el fichero completamente), y cuando volvemos a la segunda vuelta del primer bucle, FICHERO2 sigue en el final del fichero, por lo que ya no entra en el bucle más interno, y ya no se prueban las condiciones.

Una solución sería que, justo antes de empezar a leer FICHERO2, le hagas un seek() para posicionar el puntero de lectura al principio del fichero.

Lo malo es que esto es poco eficiente. Lo ideal es que toda la información sea leída una sola vez, para pasarla a memoria y hacer las comparaciones allí.

Lo ideal es leer uno de los dos ficheros, pasarlo a un hash, y luego recorrer el otro fichero, usando la línea leída como clave del hash, para comprobar si existe ese valor. Si es así, pues imprimimos la salida.
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 coincidencias en fichero

Notapor newperlero » 2011-07-15 07:12 @341

pvaldes escribiste:abro fichero 1 para lectura
abro fichero 2 para lectura
para cada linea del fichero 1
para cada linea del fichero 2
si linea1 = linea2
print linea
else "hacer otra cosa"
cierro fichero 1
cierro fichero 2


El problema está en que la línea 1 del fichero 1, a lo mejor no se corresponde con la línea 1 del fichero 2, sino con la línea 3 del fichero 2... Esta es otra opción que había pensado, pero imprime líneas repetidas a punta pala...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. foreach my $line (@fichero1) {
  2.     foreach my $line2 (@fichero2) {
  3.         if   ( $line eq $line2 ) { print FICHERO3 "#$line" }
  4.         else                     { print FICHERO3 "$line" }
  5.     }
  6. }
  7.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
newperlero
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2011-07-15 06:38 @318

Re: Buscar coincidencias en fichero

Notapor pvaldes » 2011-07-15 07:19 @346

Irás más rápido si ordenas ambos ficheros antes y si recorres el fichero sólo hasta que aparezca una coincidencia, pero de todos modos mejor echa un vistazo a lo que indica explorer

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
sort fichero1
sort fichero2
para cada linea en 1
  mientras linea1 diferente de linea 2
      print linea
      next
  si se rompe el bucle
      print \#linea
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2011-07-15 10:11 @466, editado 1 vez en total
Razón: Marcas de texto
pvaldes
Perlero nuevo
Perlero nuevo
 
Mensajes: 129
Registrado: 2011-01-22 12:56 @580

Re: Buscar coincidencias en fichero

Notapor explorer » 2011-07-15 10:13 @467

pvaldes escribiste:Irás más rápido si ordenas ambos ficheros antes
¿Por qué irá 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: Buscar coincidencias en fichero

Notapor pvaldes » 2011-07-17 06:10 @299

Porque podrías hacer comparaciones más rápidas al salirte del bucle en cuanto aparezca el resultado deseado

Y porque también podrías sofisticar la búsqueda posteriormente con relativa facilidad, centrándose en los primeros caracteres

Si busco "lavadora", me basta con saber que no empieza por l para poder desecharlo, en un fichero ordenado alfabéticamente podría añadir un puntero que saltara a la k y una condición que ignorara todo lo demás al llegar a la M aunque no hubiera encontrado la palabra, o ir extrayendo las palabras ya encontradas de la comparación de modo que no necesiten ser comprobadas de nuevo contra todas las demás líneas
pvaldes
Perlero nuevo
Perlero nuevo
 
Mensajes: 129
Registrado: 2011-01-22 12:56 @580

Re: Buscar coincidencias en fichero

Notapor explorer » 2011-07-17 06:33 @314

A medida que crece el tamaño de los archivos, la efectividad de un hash supera en mucho a una búsqueda secuencial, para estos casos en los que solo nos interesa saber de la existencia o no de una determinada clave.

Esta es mi versión:
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. ## Leemos el primer fichero
  8. my %fichero1;
  9.  
  10. open my $FICHERO1, q[<], 'kk1.txt';
  11. while (my $linea = <$FICHERO1>) {
  12.     $fichero1{$linea} = 1;
  13. }
  14. close $FICHERO1;
  15.  
  16. ## Procesamos el segundo fichero
  17. open my $FICHERO2, q[<], 'kk2.txt';
  18. open my $FICHERO3, q[>], 'kk3.txt';
  19.  
  20. while (my $linea = <$FICHERO2>) {
  21.  
  22.     if (exists $fichero1{ $linea }) {
  23.         print $FICHERO3 '#';
  24.     }
  25.  
  26.     print $FICHERO3 $linea;
  27. }
  28.  
  29. close $FICHERO2;
  30. close $FICHERO3;
  31.  
  32. __END__
  33. #linea1
  34. #linea2
  35. linea5555
  36. linea1234
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: Buscar coincidencias en fichero

Notapor newperlero » 2011-07-18 02:26 @143

Lo tengo ya perfecto, he usado el código de explorer y no solo ya me funciona todo a la perfección, sino que va más rápido que antes al tratar los ficheros enormes que tengo que tratar, gracias al hash.


Pero hay una cosa en tu código que no había visto nunca, la línea
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. open my $FICHERO1, q[<], 'kk1.txt';
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Esa [q], ¿qué indica? Si buscamos información, vemos que el operador que hace lo siguiente:

q/STRING/
'STRING'

A single-quoted, literal string. A backslash represents a backslash unless followed by the delimiter or another backslash, in which case the delimiter or backslash is interpolated
.


Esto lo había visto en expresiones regulares, pero, ¿qué sentido tiene utilizarlo para abrir un fichero?
Bueno, doy el tema por solucionado, funcionando, ¡¡gracias!!
newperlero
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2011-07-15 06:38 @318

Re: Buscar coincidencias en fichero

Notapor explorer » 2011-07-18 06:06 @296

q[<]

es lo mismo que escribir

'<'

solo que más... aparatoso... Es para que destaque visualmente el carácter que queremos usar para indicar si queremos abrir o escribir en el fichero (regla 4.3 de las Perl Best Practices: no escribir cadenas de caracteres de un solo carácter, de forma visualmente ambigua).

Así que la línea

open my $FICHERO1, q[<], 'kk1.txt';

es una forma muy larga de escribir

open my $FICHERO1, '<', 'kk1.txt';

o incluso

open my $FICHERO1, '<kk1.txt';

El operador q[] sirve para realizar un entrecomillado simple, al igual que el qq[] hace lo mismo que un entrecomillado doble.
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 30 invitados