problème de manipulation/réorganisation de fichiers

problème de manipulation/réorganisation de fichiers - Perl - Programmation

Marsh Posté le 06-04-2013 à 22:26:02    

Bonsoir à tous!
je viens solliciter vos lumières au sujet d'un script Perl visant la manipulation de fichiers. Alors voilà ce que j'ai:
     - deux fichiers comportant des lignes allant deux par deux, organisés comme ceci (même organisation pour les deux:
          >1 count:272019
          TACCTGGTTGATCCTGCCAG
          >2 count:48613
          TTTGGATTGAAGGGAGCTCTA
          >3 count:15422
          TTTGGATTGAAGGGAGCTCT
          >4 count:9818
          TTGGACTGAAGGGAGCT
          >5 count:8783
          TTGGACTGAAGGGAGCTCCCT
     - ces deux fichiers ne sont pas triés dans le même ordre, mais il devraient avoir des séquences (la deuxième ligne de chaque bloc de deux lignes qui se retrouvent dans les deux fichiers
Passons maintenant à ce que j'aimerais faire:
     - trier ces fichiers afin que les séquences qu'ils contiennent soient dans le même ordre
     - éditer la ligne de nom (la première ligne de chaque bloc de deux lignes) afin de ne garder que la valeur située après "count:" (NOTE: pour une même séquence cette valeur est différente entre le fichier 1 et le fichier 2). Pour les séquences n'apparaissant que dans l'un des fichiers, il faudrait que dans celui où elles n'apparaissent pas leur valeur de count soit égale à zéro.
Ce que j'ai fait jusque là: j'ai réussi à trier toutes mes séquences de façon à ce qu'elles soient dans le même ordre dans mes deux fichiers (j'ai créé deux nouveaux fichiers, afin de ne pas altérer mes fichiers d'origine). Mon code est comme ceci:

Code :
  1. use warnings;
  2. use strict;
  3. my $fast1="C:/Users/Moi/fichier1.fasta";
  4. open (my $IN1, "<", $fast1) or die "Impossible d'ouvrir le fichier $fast1 $!";
  5. my $fast2="C:/Users/Moi/fichier2.fasta";
  6. open (my $IN2, "<", $fast2) or die "Impossible d'ouvrir le fichier $fast2 $!";
  7. my $trie1="C:/Users/Moi/fichier1bis.fasta";
  8. open (my $OUT1, ">", $trie1) or die "Impossible d'ouvrir le fichier $trie1 $!";
  9. my $trie2="C:/Users/Moi/fichier2bis.fasta";
  10. open (my $OUT2, ">", $trie2) or die "Impossible d'ouvrir le fichier $trie2 $!";
  11. my %results;
  12. #my @tab;
  13. my ($name, $line);
  14. while($name = <$IN1> )
  15. {
  16.     $line=<$IN1>;
  17.     chomp $name;
  18.     chomp $line;
  19.     #@tab = split (/:/, $name);
  20.     #$count=$tab[1];
  21.     $results{$line}=1;
  22. }
  23. while($name = <$IN2> )
  24. {
  25.     $line=<$IN2>;
  26.     chomp $name;
  27.     chomp $line;
  28.     #@tab = split (/:/, $name);
  29.     #$count=$tab[1];
  30.     if (exists $results{$line})
  31.     {
  32.         $results{$line}++;
  33.     }
  34. }
  35. foreach $line (keys %results)
  36. {
  37.    if ($results{$line} == 1)
  38.    {
  39.         print $OUT1 "$line\n";
  40.    }
  41.    if ($results{$line}==2)
  42.    {
  43.         print $OUT1 "$line\n";
  44.         print $OUT2 "$line\n";
  45.    }
  46.   else
  47.   {
  48.         print $OUT2 "$line\n";
  49.    }
  50. }
  51. close ($IN1);
  52. close ($IN2);
  53. close ($OUT1);
  54. close ($OUT2);
  55. print "Programme termine";
  56. <STDIN>


Bon alors, comme je l'ai dit, ce code semble marcher. Cependant, mon problème est: je ne sais pas comment faire pour garder la valeur de count et qu'elle reste bien associée à la ligne à laquelle elle correspondait dans le fichier d'origine. Au début je voulais faire un $results{$count}=1, etc (comme pour la séquence), mais le problème est que je n'ai pas le même count dans le deux fichiers pour une même séquence, du coup, je suis perdu... Comme vous pouvez le voir par les lignes commentées que j'ai laissées dans mon code, j'avais aussi une idée d'y stocker dans un tableau, mais en fait, je ne vois pas comment spécifier que cette valeur doit rester associée à la séquence de la ligne suivante...
Je dois bien avouer être une énorme bille en hash et encore plus en hash de hash que je ne comprend absolument pas, bien que je lise cours et exemples, et donc un petit coup de main serait le bienvenu...


---------------
Je n'ai pas une case en moins, je commence juste à compter à partir de zéro
Reply

Marsh Posté le 06-04-2013 à 22:26:02   

Reply

Marsh Posté le 08-04-2013 à 21:11:57    

Je procéderais ainsi:
 

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. sub processFiles (@) {
  7.  my %data;
  8.  my $index = 0;
  9.  foreach my $file (@_) {
  10.    open my $handle, "<", $file;
  11.    my ($compte, $sequence);
  12.    while (defined($compte = <$handle> ) and defined($sequence = <$handle> )) {
  13.      # suppression des blancs éventuels et de la fin de ligne
  14.      map {chomp; s/^\s+//; s/\s+$//;}($compte, $sequence);
  15.      last unless (length($compte) * length($sequence) > 0);
  16.      # verification de la cohérence des données lues
  17.      $compte =~ s/^.*count:\s*//;
  18.      last unless ($compte =~ /\d+/ and $sequence =~ /[ACGT]+/);
  19.      # On pourrait signaler une erreur ici si necessaire
  20.  
  21.      unless (defined(${data}{$sequence})) {
  22.         $data{$sequence} = [];
  23.      }
  24.      $data{$sequence}->[$index] = $compte;
  25.    }
  26.    close $handle;
  27.    ++$index;
  28.  }
  29.  # A ce stade, %data a toute l'information glanée dans les fichiers
  30.  # On va filtrer sur le champ $data{$sequence}->[i] pour le (i+1)-ième fichier
  31.  $index = 0;
  32.  foreach my $file (@_) {
  33.    my ($before, $after) = split(/.([^.]+)$/, $file);
  34.    $file = $before."bis.".$after;
  35.    open my $handle, ">", $file;
  36.    foreach (sort {$a cmp $b} (keys %data)) {
  37.      # $handle $data{$_}->[$index] // 0 renvoie $data{$_}->[$index] s'il est défini et 0 sinon
  38.      say $handle $data{$_}->[$index] // 0;
  39.      say $handle $_;
  40.    }
  41.    close $handle;
  42.    ++$index;
  43.  }
  44. }
  45.  
  46. my @infiles;
  47. push @infiles, 'fichier1.fasta';
  48. push @infiles, 'fichier2.fasta';
  49. processFiles(@infiles);


 
C'est du code relativement générique, qui peut marcher avec plus de 2 fichiers en entrée le cas échéant.
Je crée un hash, %data, dont les clés sont les séquences GTAC... lues (la seule hypothèse, ici, est que chaque séquence n'est présente qu'une fois par fichier, mais sinon, cela n'aurait guère de sens), et pour chaque clé, la valeur est un tableau ($data{$sequence} = [];) dont la i-ème entrée est la valeur de compte lue dans le (i+1)-ième fichier ($data{$sequence}->[$index] = $compte;) (ou undef, si la séquence n'est pas dans le fichier).  
A toi d'adapter selon tes besoins, je te donnerais plus d'explications si nécessaire.
 
A+,


Message édité par gilou le 08-04-2013 à 21:35:31

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed