5 de abril de 2011

Extraer de un texto líneas con el contenido deseado

A continuación os dejo un sencillo código para extraer las líneas deseadas de un texto dándole como parámetros el texto y un array con las palabras o patrones que deben estar presentes en las líneas a extraer.

Modificaciones de este código nos pueden ser muy útiles en diversos problemas bioinformáticos, cuando tenemos archivos con muchas líneas de datos y sólo queremos utilizar o visualizar unas pocas.

En próximas entradas utilizaremos este código para extraer por ejemplo los átomos deseados de un fichero de coordenadas atómicas en formato PDB.

 my $source_text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n  
 Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n  
 Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n  
 Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";  
   
 my @patterns;  
 push(@patterns, 'adipisicing');  
 push(@patterns, '/dolor/');  
   
 my $extracted_text = join('',extract_lines_from_text($source_text,\@patterns));  
   
 print "$extracted_text\n";  
   
 # Extract lines from text with the desired patterns  
 sub extract_lines_from_text {  
   
      my ($text, $patterns) = @_;  
   
      my @data;  
      my @lines = split("\n",$text);  
   
      foreach my $line (@lines){  
           foreach my $pattern (@{$patterns}){  
                if ($pattern =~ /^\/(.+)\/$/){  
                     if ($line =~ /$1/){  
                          push(@data,$line);  
                          last;  
                     }  
                } else {  
                     if ($line =~ /\Q$pattern\E/){  
                          push(@data,$line);  
                          last;  
                     }  
                }  
           }  
      }  
   
      return @data;  
   
 }  
   

3 comentarios:

  1. En versión one-liner:
    perl -lne '/dolor/ || /adipisicing/ and print' corpus.txt

    Más sobre el tema en:
    http://www.eead.csic.es/compbio/material/bioinfoPerl/node89.html

    ResponderEliminar
  2. Se puede aprovechar una característica de Perl, muy interesante: dentro de extract_lines_from_text(), y antes del bucle que recorre las líneas, se puede crear una expresión regular que sea un conjunto de alternativas con todos los patrones que estamos buscando. Así, nos ahorramos un bucle for y el procesamiento es muchísimo más rápido, ya que la expresión regular solo es interpretada una vez.

    ResponderEliminar
  3. Uniendo los patrones previamente el código quedaría:

    sub extract_lines_from_text {

    my ($text, $patterns) = @_;

    my @data;
    my @lines = split("\n",$text);

    my @unique_patterns;
    foreach my $pattern (@{$patterns}){
    if ($pattern =~ /^\/(.+)\/$/){
    push(@unique_patterns,$1);
    } else {
    push(@unique_patterns,'\Q'.$pattern.'\E');
    }
    }

    my $unique_pattern = join('|',@unique_patterns);
    foreach my $line (@lines){
    if ($line =~ /$unique_pattern/){
    push(@data,$line);
    }
    }

    return @data;

    }

    Sería 1/20 veces más rápido, si procesamos ficheros muy grandes puede ser ventajoso.

    ResponderEliminar