• Publicidad

Consulta sobre búsqueda dentro de 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.

Consulta sobre búsqueda dentro de un archivo

Notapor chodar » 2012-12-27 09:44 @447

Hola, amigos.

Estoy empezando en esto de Perl y parece que se me ocurrió hacer algo muy complicado... La cosa es la siguiente: tengo un archivo de texto que contiene una lista de palabras todas distintas (cerca de 15 000, con un formato del tipo FBxxxxxxxx) y que necesito encontrar y reemplazarlas (más bien agregarles un prefijo, para que queden prefix-FBxxxxxxxx) en un archivo que tiene cerca de 8 000 000 de líneas.

Había pensado en construir un array con cada palabra y luego en un ciclo ir buscando cada una y reemplazándola en caso de encontrarla. ¿Será esa la forma más conveniente?

¿Alguna idea para el script?
Saludos y gracias.
chodar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2012-12-27 09:31 @438

Publicidad

Re: Consulta sobre búsqueda dentro de un archivo

Notapor explorer » 2012-12-27 19:28 @853

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

¿Cómo es el formato del archivo grande? Supongo que igual que el primero: una entrada por cada línea.

En ese caso, la forma más conveniente es, primero, meter las 15 000 palabras en un hash. Luego, vas recorriendo las líneas del archivo grande. Por cada línea, extraes su entrada. Si existe esa entrada en el hash creado antes, entonces ya sabes que esa entrada del segundo archivo existe como palabra en el primero, así que procedes a agregarle el prefijo. Luego, tanto en el caso de ponerle el prefijo, como si no, grabas la línea en el archivo resultado (que antes habrás abierto en modo escritura, claro).

Si en vez de hash usaras un array, estarías obligado a realizar un doble bucle por cada una de los 8 000 000 de líneas comparándolas con las 15 000 palabras... y eso son muchas vueltas.
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 búsqueda dentro de un archivo

Notapor chodar » 2012-12-27 19:49 @867

Gracias por la respuesta, explorer.

Desgraciadamente, el segundo archivo (el grande) no es una lista simple como la primera. Está compuesta de 7.6 millones de líneas con información separada por espacios, que en algunos casos coinciden con lo que está en la lista única (y que son a los que necesito agregar el prefijo).

Ya había logrado algo con un doble bucle, pero en una versión resumida (un archivo de 15 líneas y una lista de 4 palabras). No me manejo mucho con los hash así es que tendré que estudiar un poco el tema. Claro que si para su uso es requisito que ambos archivos tengan un formato donde cada fila tenga una entrada, pues estoy frito.

Saludos, gracias por la bienvenida y la respuesta.
chodar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2012-12-27 09:31 @438

Re: Consulta sobre búsqueda dentro de un archivo

Notapor explorer » 2012-12-27 20:54 @912

Si ese archivo sigue un formato, pues lo que queremos saber es cómo es ese formato. Con que publiques algunas de esas líneas, nos vale.

En la mayor parte de las ocasiones, lo tienes resuelto con una expresión regular, o usando split(), unpack() o substr().

Y sí: debes usar hash. La diferencia de velocidad puede ser de 10 000 a 1.
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 búsqueda dentro de un archivo

Notapor chodar » 2012-12-27 21:04 @919

¡Ja,ja...! En realidad debería haber empezado por ahí... He aquí un extracto del archivo gigante:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
# BLASTP 2.2.27+
# Query: AGAP000009|AGAP000009-RB
# Database: dm.dg.md.ag.pep
# Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 46 hits found
AGAM|AGAP000009-RB      AGAM|AGAP000009-RB      100.00  1108    0       0       1       1108    1       1108    0.0     2312
AGAM|AGAP000009-RB      AGAM|AGAP000009-RC      100.00  694     0       0       1       694     1       694     0.0     1468
AGAM|AGAP000009-RB      AGAM|AGAP000009-RC      99.76   413     1       0       696     1108    793     1205    0.0      820
AGAM|AGAP000009-RB      AGAM|AGAP000009-RA      100.00  688     0       0       1       688     1       688     0.0     1452
AGAM|AGAP000009-RB      AGAM|AGAP000009-RA      98.57   419     6       0       690     1108    852     1270    0.0      821
AGAM|AGAP000009-RB      FBpp0146500     63.82   691     232     9       1       689     1       675     0.0      947
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


El punto es que algunas de las líneas tienen valores FBppxxxxxx que debería decir prefix|FBppxxxxxx y pues esos son los que tengo en la lista. Ahora, esta estructura no es fija: tiene un encabezado, descrito por los 4 "#" al principio, pero dentro de este cambia el "query" y el número de "hits founds" lo que hace variar el largo de líneas hasta el siguiente "#Blastp"... ¿se entiende?

Saludos de nuevo y gracias por tu tiempo.
chodar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2012-12-27 09:31 @438

Re: Consulta sobre búsqueda dentro de un archivo

Notapor explorer » 2012-12-28 18:09 @797

Bueno, tampoco nos dices si las entradas que buscas están siempre en la segunda columna, como vemos en el ejemplo. O si también se pueden repetir en el resto de columnas...

Si suponemos el caso sencillo (siempre aparece en la segunda columna y solo en esa columna), y que las columnas están separadas (o pueden quedarse separadas) con tabuladores, entonces consiste en extraer la segunda columna, ver si es una de las palabras que buscamos, y si es así, modificarla con el prefijo.

Ejemplo corto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use File::Slurp;
  4.  
  5. my @archivo_peque  = qw(                                # palabras a buscar (primer archivo)
  6.     FBpp0146499
  7.     FBpp0146500
  8.     FBpp0146501
  9. );
  10.  
  11. my %palabras_a_buscar;
  12.  
  13. for my $palabra (@archivo_peque) {
  14.     $palabras_a_buscar{$palabra} = 1;                   # recordamos cada palabra a buscar
  15. }
  16.  
  17. ## Recorremos las líneas del archivo grande (segundo archivo)
  18. my @archivo_grande = read_file('kk.txt', chomp => 1);
  19.  
  20. for my $linea (@archivo_grande) {
  21.  
  22.     next if $linea =~ /^#/;                             # saltamos si es un comentario
  23.  
  24.     my @columnas = split " ", $linea;
  25.  
  26.     if ($palabras_a_buscar{$columnas[1]}) {             # si la $segunda_columna está entre las palabras a buscar...
  27.         $columnas[1] = "prefix|$columnas[1]";           # ... la modificamos
  28.     }
  29.  
  30.     # rehacemos la línea. Suponemos el caso sencillo de separar las columnas con tabuladores
  31.     $linea = join "\t", @columnas;
  32. }
  33.  
  34. ## Imprimimos el resultado
  35. say join "\n", @archivo_grande;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
y lo que sale es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
# BLASTP 2.2.27+
# Query: AGAP000009|AGAP000009-RB
# Database: dm.dg.md.ag.pep
# Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 46 hits found
AGAM|AGAP000009-RB      AGAM|AGAP000009-RB      100.00  1108    0       0       1       1108    1       1108    0.0     2312
AGAM|AGAP000009-RB      AGAM|AGAP000009-RC      100.00  694     0       0       1       694     1       694     0.0     1468
AGAM|AGAP000009-RB      AGAM|AGAP000009-RC      99.76   413     1       0       696     1108    793     1205    0.0     820
AGAM|AGAP000009-RB      AGAM|AGAP000009-RA      100.00  688     0       0       1       688     1       688     0.0     1452
AGAM|AGAP000009-RB      AGAM|AGAP000009-RA      98.57   419     6       0       690     1108    852     1270    0.0     821
AGAM|AGAP000009-RB      prefix|FBpp0146500      63.82   691     232     9       1       689     1       675     0.0     947
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Este ejemplo no lo debes aplicar directamente a tu problema porque trabaja con los dos archivos en memoria, siendo ideal que el segundo archivo se recorra línea a línea, y dejando el resultado en un tercer archivo (el de resultado). Lo importante es ver lo fácil que es hacer la búsqueda de coincidencia de las palabras (bueno, realmente no hay búsqueda).
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 búsqueda dentro de un archivo

Notapor chodar » 2012-12-28 18:45 @822

Hola,

Siempre se me va algo... Con respecto a donde puede aparecer, no es solo en la segunda columna, puede ser en la primera o incluso donde dice "# Query: AGAP000009|AGAP000009-RB", es decir, puede ser "# Query: FBppxxxxxx" que aun siendo comentarios, necesita el reemplazo.

Saludos y gracias nuevamente.
chodar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2012-12-27 09:31 @438

Re: Consulta sobre búsqueda dentro de un archivo

Notapor explorer » 2012-12-28 18:53 @828

Pues si aparece en más sitios, lo único que hay que hacer es aumentar el número de if(). El resto es igual.
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 búsqueda dentro de un archivo

Notapor chodar » 2012-12-28 19:19 @846

Bien, le daré vueltas el fin de semana y si me asalta alguna duda, aviso...

¡¡Gracias por la ayuda!!
chodar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2012-12-27 09:31 @438

Re: Consulta sobre búsqueda dentro de un archivo

Notapor explorer » 2012-12-29 10:48 @492

Por aquí estaremos :)

Si puede aparecer en la primera columna, solo hay que poner otro if() parecido al que te puse, pero para $columnas[0]. Y para contemplar el caso de la aparición en una línea de comentario, hay que quitar el next(), y sustituirlo por unas líneas como estas:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ($linea =~ m/^#/) {                                    # si la línea es un comentario (comienza por '#')
  2.         if ((my $palabra) = $linea =~ m/Query: (FBpp\w+)/) {  # si contiene una palabra sospechosa, la capturamos con los paréntesis
  3.             if ($palabras_a_buscar{$palabra}) {               # y esa palabra es de las que estamos buscando
  4.                 $linea =~ s/$palabra/prefix|$palabra/;        # le ponemos el prefijo
  5.             }
  6.         }
  7.         next;                                             # no hace falta seguir mirando más, pasamos a la siguiente
  8.     }
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: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

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