PERL

Résolu
wafa_o Messages postés 112 Statut Membre -  
lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   -
Bonjour,

J'ai besoin de vos lumières ...
J'ai un fichier que je place dans un tableau avec plusieurs colonnes. L'une des colonnes contient des valeurs différentes. Par exemple :

145
175
652
854
956852
452
615
245

Mon problème c'est la valeur immense, ici 956852. Je voudrais qu'en cas de valeurs énorme, elle soit remplacer par 0 ou la valeur précédente (ici 854).

Merci d'avance pour votre aide
Configuration: Windows Vista / Firefox 3.5.8

18 réponses

  1. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Ok.
    Ca te va?
    lami20j@debian-acer:~/perl$ cat col5.txt 
    100108 17:00 64
    100108 18:00 64
    100108 18:00 28
    100104 01:00 333
    100108 18:00 3334
    100108 18:00 5
    100108 18:00 7
    lami20j@debian-acer:~/perl$ cat colonne6.pl 
    #!/usr/bin/perl
    use strict;use warnings;
    my (@col,%h);
    my $f="col5.txt";
    open F,"$f" or die "E/S : $!\n";
    
    while(<F>){
      chomp;
      my @l=split;
      $h{length($l[2])}++;
    }
    
    my @tri =sort {$h{$b} <=> $h{$a}} keys %h;
    my $max = (shift @tri) + 1;
    
    open F,"$f" or die "E/S : $!\n";
    while(<F>){
      chomp;
      my @l=split;
      (length($l[2])<$max+1)?print "$_\n":print "@l[0..1] 0\n";
    }
    lami20j@debian-acer:~/perl$ perl colonne6.pl
    100108 17:00 64
    100108 18:00 64
    100108 18:00 28
    100104 01:00 333
    100108 18:00 0
    100108 18:00 5
    100108 18:00 7
    
    1
    1. wafa_o Messages postés 112 Statut Membre 2
       
      :D Ca fonctionne !!!!!!!!!!!!!
      Merci. Il ne me reste plus qu'à comprendre ton programme ...
      0
  2. wafa_o Messages postés 112 Statut Membre 2
     
    Je remonte le post ...
    0
  3. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Salut,

    Qu'appelles tu immense? Il y a un minimum accepté?
    Et le fait de dire que tu as une colonne ça n'aide pas trop?
    Quelle colonne? Il y a quoi comme séparateur entre les champs?

    P.S. Pour ne pas dire que le titre de message ne dit rien ou il dit trop ;-)
    0
  4. wafa_o Messages postés 112 Statut Membre 2
     
    Immense c'est à dire 10 fois les valeurs que l'on trouve dans la colonne.
    Par exemple si la valeur est 10 fois supérieur aux autres valeurs, elle est considérée comme "immense".
    Il y a 5 colonnes séparées par des espaces. Enfin l'histoire des colonnes, c'est à titre indicatif. Même si tu prends l'exemple d'une colonne, je pourrais toujours l'adapter ensuite.

    PS : C'était pour eveiller la curiosité mais j'ai compris, ne plus recommencer ;-)
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Par exemple si la valeur est 10 fois supérieur aux autres valeurs,
    Je ne comprends pas ;-(
    0
  7. wafa_o Messages postés 112 Statut Membre 2
     
    Je ne suis pas douée en explication :((( . Je vais essayer de reprendre...

    Voilà les valeurs dans ma table :
    145
    175
    652
    854
    956852
    452
    615
    245

    On est d'accord que 956852 est la valeur immense.
    Dans la colonne on trouve des valeurs de l'ordre des centaines, soit un nombre à trois chiffres. Lorsque le nombre est composé de plus de 3 chiffres, il y a une erreur.
    452 est composé de 3 chiffres. On le garde.
    854 est composé de 3 chiffres. On le garde.
    956852 est composé de 6 chiffres. On NE le garde PAS car il y a plus de 3 chiffres.

    :s :s J'espère avoir été plus claire
    0
  8. xav3601 Messages postés 3390 Statut Membre 312
     
    Et ben avant d'insérer une valeur tu multiplie la valeur précédente par 10 et tu fais un test!
    si la valeur est supérieur au résultat tu mets la valeur précédentes sinon tu met ta valeur courante ^^

    Attention, a ne pas faire sur la premiere valeur ^^
    0
    1. wafa_o Messages postés 112 Statut Membre 2
       
      C'est ce que j'ai fait. Je récupère la valeur précédente, je la multiplie par 100. Mon problème c'est la première valeur du test. Ici je recupère 189275. Comment faire quand cette valeur n'est pas bonne.


      Ici ca fonctionne :

      #!/usr/bin/perl
      my @tab;

      foreach(<DATA>){
      chomp($_);
      my @v=split(/ /,$_);
      push (@valeur,$v[0]);
      }
      close(DATA);

      for (my $j=0; $j<@valeur; $j++)
      {
      $j--;
      my $essai= 100*$valeur[$j];
      $j++;

      if($valeur[$j]>$essai) {
      print "0\n";
      }
      else {print "$valeur[$j]\n";}
      }



      __END__
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      189275

      Résultat :
      109190
      188058
      178240
      102657
      86015
      197589
      0
      116507
      195971
      232993
      0
      189275

      ==> tout est OK


      Ici ca ne fonctionne pas :
      #!/usr/bin/perl
      my @tab;

      foreach(<DATA>){
      chomp($_);
      my @v=split(/ /,$_);
      push (@valeur,$v[0]);
      }
      close(DATA);

      for (my $j=0; $j<@valeur; $j++)
      {
      $j--;
      my $essai= 100*$valeur[$j];
      $j++;

      if($valeur[$j]>$essai) {
      print "0\n";
      }
      else {print "$valeur[$j]\n";}
      }



      __END__
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      18927525


      Résultat :
      109190
      188058
      178240
      102657
      86015
      197589
      0
      116507
      195971
      232993
      0
      18927525


      ==> PROBLEME, je veux avoir :
      Résultat :
      109190
      188058
      178240
      102657
      86015
      197589
      0
      116507
      195971
      232993
      0
      0
      0
  9. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Salut,

    Comme tu ne veux pas donner la structure de ton fichier pour savoir sur quelle colonne on doit réagir, alors je te laisse adapter.

    J'ai ajouter plusieurs lignes et aussi des lignes consécutives avec des valeurs plus grandes que 999 pour tester

    Voici les deux cas
    Cas 1: remplacer avec zéro si la longueur est plus grande que 3
    lami20j@debian-acer:~$ cat colonne0.pl 
    #!/usr/bin/perl
    use strict;use warnings;
    while(<DATA>){
      /\d{4,}/?print "0\n":print;
    }
    __END__
    145
    175
    652
    854
    956852
    452
    615
    956852
    245
    956852
    956852
    956852
    lami20j@debian-acer:~$ perl colonne0.pl
    145
    175
    652
    854
    0
    452
    615
    0
    245
    0
    0
    0
    


    Cas 2: remplacer avec la valeur précédente si la longueur est plus grande que 3

    lami20j@debian-acer:~$ cat colonne1.pl 
    #!/usr/bin/perl
    use strict;use warnings;
    my @col;
    while(<DATA>){
      chomp;
      unshift @col,$_ if length($_)<4; 
      print "$col[0]\n";
    }
    __END__
    145
    175
    956852
    652
    854
    956852
    956852
    452
    615
    956852
    956852
    956852
    956852
    956852
    245
    956852
    567
    lami20j@debian-acer:~$ perl colonne1.pl
    145
    175
    175
    652
    854
    854
    854
    452
    615
    615
    615
    615
    615
    615
    245
    245
    567
    
    0
    1. wafa_o Messages postés 112 Statut Membre 2
       
      Les deux scripts pourraient fonctionner, seulement je me pose une question et j'aurais du y réfléchir avant. Ca fonctionne pour un de mes fichiers mais pas pour les autres car les valeurs sont supérieurs à trois chiffres. Ici le script fonctionnerait si j'avais indiqué 7 au lieu de 4.
      Pour ces données ca ne fonctionne pas,
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      18927525

      En résumé, ton script réponds parfaitement à mon problème. C'est mon problème qui est mal expliqué :(
      0
  10. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Le cas 2 amélioré (je garde dans le tableau que le 1er élément qui sera la valeur affichée).
    Le script précédent augmenterait le tableau d'un pour chaque élément de longueur plus petit que 4.
    Dans cette version le tableau contient un seul élément
    lami20j@debian-acer:~$ cat perl/colonne2.pl
    #!/usr/bin/perl
    use strict;use warnings;
    my @col;
    while(<DATA>){
      chomp;
      unshift @col,$_ if length($_)<4; 
      splice(@col,1);
      print @col+0,": @col\n";
    }
    __END__
    145
    175
    956852
    652
    854
    956852
    956852
    452
    615
    956852
    956852
    956852
    956852
    956852
    245
    956852
    567
    lami20j@debian-acer:~$ perl perl/colonne2.pl
    1: 145
    1: 175
    1: 175
    1: 652
    1: 854
    1: 854
    1: 854
    1: 452
    1: 615
    1: 615
    1: 615
    1: 615
    1: 615
    1: 615
    1: 245
    1: 245
    1: 567
    
    0
    1. wafa_o Messages postés 112 Statut Membre 2
       
      En fait, je ne comprends pas ton programme.
      J'ai essayé ca :

      #!/usr/bin/perl
      use strict;use warnings;
      my @col;
      while(<DATA>){
      chomp;
      unshift @col,$_ if length($_)<7;
      splice(@col,1);
      print @col+0,": @col\n";
      }

      __END__
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      18927525


      Et voilà le résultat :
      1: 109190
      1: 109190
      1: 109190
      1: 109190
      1: 86015
      1: 86015
      1: 86015
      1: 86015
      1: 86015
      1: 86015
      1: 86015
      1: 86015
      0
    2. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571 > wafa_o Messages postés 112 Statut Membre
       
      Je te l'ai dit que je ne comprends pas ce que tu veux.
      Pourquoi 7 et pas 6?
      Comment tu choisi le minimum?
      Et puis comme toujours on ne travaille pas sur le même fichier.

      Voici ce que j'ai avec ton exemple, ça semble bon chez moi, non?
      Je vais t'expliquer l'algo de programme, mais d'abord il faut qu'on fait les tests sur le même fichier.
      lami20j@debian-acer:~$ cat perl/colonne2.pl 
      #!/usr/bin/perl
      use strict;use warnings;
      my @col;
      while(<DATA>){
        chomp;
        unshift @col,$_ if length($_)<7; 
        splice(@col,1);
        print @col+0,": @col\n";
      }
      __END__
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      18927525
      lami20j@debian-acer:~$ perl perl/colonne2.pl 
      1: 109190
      1: 188058
      1: 178240
      1: 102657
      1: 86015
      1: 197589
      1: 197589
      1: 116507
      1: 195971
      1: 232993
      1: 232993
      1: 232993
      
      0
    3. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571 > wafa_o Messages postés 112 Statut Membre
       
      Re,

      Pour comprendre ce que le programme fait regarde ça
      T'as bien compris que dans le tableau je mets tout sauf le immense, ce qui permettra de garder une trace sur le précedent
      splice permet tout simplement de garder dans le tableau que le 1 élément, c'est ce qui nous intéresse (regarde en gras)

      lami20j@debian-acer:~/perl$ cat colonne3.pl 
      #!/usr/bin/perl
      use strict;use warnings;
      my @col;
      while(<DATA>){
        chomp;
        unshift @col,$_ if length($_)<7; 
        print "\@col : @col\n";
      }
      __END__
      109190
      188058
      178240
      102657
      86015
      197589
      106909268
      116507
      195971
      232993
      51982476
      18927525
      lami20j@debian-acer:~/perl$ perl colonne3.pl
      @col : 109190
      @col : 188058 109190
      @col : 178240 188058 109190
      @col : 102657 178240 188058 109190
      @col : 86015 102657 178240 188058 109190
      @col : 197589 86015 102657 178240 188058 109190
      @col : 197589 86015 102657 178240 188058 109190
      @col : 116507 197589 86015 102657 178240 188058 109190
      @col : 195971 116507 197589 86015 102657 178240 188058 109190
      @col : 232993 195971 116507 197589 86015 102657 178240 188058 109190
      @col : 232993 195971 116507 197589 86015 102657 178240 188058 109190
      @col : 232993 195971 116507 197589 86015 102657 178240 188058 109190
      
      0
    4. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571 > lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention  
       
      Tu as aussi remarqué que l'élément est rajouté au début ce qui veut dire que
      1ère ligne :                     1er élément
      2ème ligne : si condition alors  2eme élément 1 élément
                   sinon               1er élément - donc je garde le précedent
      3ème ligne : si condition alors  3ème élément 2eme élément 1 élément
                   sinon alors         le contenu de tableau ne change pas
      
      etc.
      

      Toutefois il y a un cas qui ne sera rempli, quand la 1ère ligne ne rempli pas la condition, il n'y a pas de valeur précédente.
      0
    5. wafa_o Messages postés 112 Statut Membre 2 > lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention  
       
      Je comprends mieux merci.

      Pourquoi 6 ou 7 et pas 3 ? je t'explique. En fait, j'ai plusieurs fichiers. Pour certains, c'est 3, d'autres 2, d'autres 8, d'autres 7. Je ne veux pas fixer la valeur, enfin je devrais dire que je ne peux pas. Ces fichiers changent tout le temps. Une fois j'ai des nombres composés de 3 chiffres, une autre fois les nombres sont composés de 8 chiffres. C'est indépendant de ma volonté, je reçois les fichiers comme ca.
      C'est pour celà que je suis partie sur le script que j'ai posté.

      Quand la 1ère ligne ne rempli pas la condition, il n'y a pas de valeur précédente : Ca m'embete un peu. J'ai eu le même problème dans le programme que j'ai posté. Une valeur n'est pas testée ...
      0
  11. wafa_o Messages postés 112 Statut Membre 2
     
    Merci lami20j, j'avais pas vu tes messages. Je suis partie sur la piste de xav3601 mais toujours avec des difficultés ....
    0
    1. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
       
      Re,

      Tu ne dis en revanche si ça te conviens ce que je t'ai donné.
      0
  12. wafa_o Messages postés 112 Statut Membre 2
     
    C'est en phase de test, je te dis ca dans qq'minutes ;)
    0
  13. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    lami20j@debian-acer:~/perl$ cat colonne5.pl 
    #!/usr/bin/perl
    use strict;use warnings;
    my @col;
    print "Max accepté : ";
    chomp(my $n=<STDIN>);
    while(<>){
      chomp;
      my @l=split;
      (length($l[2])<$n)?print "$_\n":print "@l[0..1] 0\n";
    }
    lami20j@debian-acer:~/perl$ perl colonne5.pl col1.txt
    Max accepté : 4
    100108 19:00 519
    100108 19:00 625
    100105 19:00 399
    100105 17:00 398
    100105 19:00 433
    100108 19:00 352
    100107 18:00 430
    lami20j@debian-acer:~/perl$ perl colonne5.pl col2.txt
    Max accepté : 6
    100108 17:00 19758
    100108 18:00 25773
    100108 18:00 85174
    100104 01:00 0
    100108 18:00 11650
    100108 18:00 19597
    100108 18:00 23299
    lami20j@debian-acer:~/perl$ perl colonne5.pl col3.txt
    Max accepté : 7
    100104 22:00 833308
    100107 19:00 237479
    100107 19:00 0
    100110 23:00 625874
    100110 23:00 740779
    100106 22:00 0
    
    0
  14. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Quand la 1ère ligne ne rempli pas la condition, il n'y a pas de valeur précédente : Ca m'embete un peu. J'ai eu le même problème dans le programme que j'ai posté. Une valeur n'est pas testée ...

    Oui, ça t'embête, je suis d'accord, mais tu veux mettre quoi à la place.
    En revanche avec 0 à la place ça ne pose pas de problèmes, puisque pas besoin de valeur précédente
    lami20j@debian-acer:~/perl$ cat col4.txt 
    100104 01:00 106909268
    100108 17:00 19758
    100108 18:00 25773
    100108 18:00 85174
    100104 01:00 106909268
    100108 18:00 11650
    100108 18:00 19597
    100108 18:00 23299
    lami20j@debian-acer:~/perl$ perl colonne5.pl col4.txt
    Max accepté : 6
    100104 01:00 0
    100108 17:00 19758
    100108 18:00 25773
    100108 18:00 85174
    100104 01:00 0
    100108 18:00 11650
    100108 18:00 19597
    100108 18:00 23299
    

    0
  15. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Je pense toujours que la multiplication n'est pas obligatoire.

    Dans ce cas, les valeurs considérées comme "normale" sont les nombres à 4 chiffres car elles sont plus nombreuses. Toutefois, on peut accepter les nombres de 4-1 chiffres et 4+1 chiffres

    Donc la règle est alors
    - le nombre de chiffre en fonction du nombre le plus grande de ligne qui contient ce numéro, Nchiffres sur NLignes
    - on accepte le NChiffres-1 et +1

    C'est ça la règle?

    Alors en ce cas

    64
    54
    28
    333
    3344
    5
    7

    NChiffres = 2 puisque NLignes=3
    et on accepte NChiffres=1 et NChiffres=3

    On doit obtenir

    64
    54
    28
    333
    0
    5
    7

    C'est ça?
    0
  16. wafa_o Messages postés 112 Statut Membre 2
     
    Oui c'est bien cela
    0
  17. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Alors il faut parcourir une fois le fichier pour trouver le NChiffres, puisqu'on ne pas savoir d'avance le min, et ensuite c'est facile.
    Tes fichiers peuvent contenir jusqu'à quel nombre de lignes?
    0
  18. wafa_o Messages postés 112 Statut Membre 2
     
    Jusqu'à 30 lignes
    0
  19. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Ok, c'est bien.
    En fait je parcours une fois le fichier et je stocke dans un hash
    la cle = la longueur de champ
    la valeur = un compteur qui donnera le NLignes

    Maintenant on a ce qu'il nous faut (NChiffres et NLignes) pour pouvoir mettre la condition.

    Ensuite je garde la valeur la plus présente (dans ce cas le 2 est 3 fois)
    Et puis c'est simple
    Toutes les champs plus petits (on teste la longueur, c'est suffisant) que 4 puisqu'on accepte 2-1 et 2+1
    Il fallait que je fasse directement $max+2 au lieu d'ajouter deux fois 1
    lami20j@debian-acer:~/perl$ cat colonne6.pl 
    #!/usr/bin/perl
    use strict;use warnings;
    my (@col,%h);
    my $f="col5.txt";
    open F,"$f" or die "E/S : $!\n";
    
    while(<F>){
      chomp;
      my @l=split;
      $h{length($l[2])}++;
    }
    my @tri =sort {$h{$b} <=> $h{$a}} keys %h;
    my $max = shift @tri;
    open F,"$f" or die "E/S : $!\n";
    while(<F>){
      chomp;
      my @l=split;
      (length($l[2])<$max+2)?print "$_\n":print "@l[0..1] 0\n";
    }
    


    Mais je viens de penser à un cas qu'on a oublié. Si jamais il y a deux champs avec NLignes égal ou plusieurs, on choisi quoi?
    Puisque sinon le plus petit est pris en compte.
    lami20j@debian-acer:~/perl$ cat col5.txt 
    100108 17:00 64
    100108 18:00 64
    100108 18:00 28
    100104 01:00 333
    100108 18:00 3334
    100108 18:00 5
    100108 18:00 7
    100108 18:00 55555
    100108 18:00 55555
    100108 18:00 55555
    lami20j@debian-acer:~/perl$ perl colonne6.pl
    100108 17:00 64
    100108 18:00 64
    100108 18:00 28
    100104 01:00 333
    100108 18:00 0
    100108 18:00 5
    100108 18:00 7
    100108 18:00 0
    100108 18:00 0
    100108 18:00 0
    

    0
    1. wafa_o Messages postés 112 Statut Membre 2
       
      Merci pour les explications, shift sert à quoi ?

      Pour le cas que l'on a oublié, je ne pense pas qu'il se produira ou devrais je dire je suis certaines qu'il ne se produira pas.
      0
      1. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571 > wafa_o Messages postés 112 Statut Membre
         
        Re,

        Le tableau @tri contient la fréquence d'apparition
        2->3 fois
        etc.
        $max = 2 le 1er élément de tableau qu'on obtiens avec shift, j'aurai pu utiliser directement $tri[0].

        Voir la fonction shift

        Tu peux utiliser des print dans le script pour voir ce qui se passe.
        Pour mieux comprendre ce que fait le script voilà
        lami20j@debian-acer:~/perl$ cat colonne6.pl 
        #!/usr/bin/perl
        use strict;use warnings;
        my (@col,%h);
        my $f="col5.txt";
        open F,"$f" or die "E/S : $!\n";
        
        while(<F>){
          chomp;
          my @l=split;
          $h{length($l[2])}++;
        }
        print "NChiffre: $_ => NLignes: $h{$_}\n" for keys %h;
        my @tri =sort {$h{$b} <=> $h{$a}} keys %h;
        print "\@tri: @tri\n";
        my $max = shift @tri;
        print "On choisi la valeur \$max = $max qui est sur $h{$max} NLignes\n";
        print "Ce qui reste dans le tableau après shift \@tri: @tri\n";
        #open F,"$f" or die "E/S : $!\n";
        #while(<F>){
        #  chomp;
        #  my @l=split;
        #  (length($l[2])<$max+2)?print "$_\n":print "@l[0..1] 0\n";
        #}
        lami20j@debian-acer:~/perl$ perl colonne6.pl
        NChiffre: 1 => NLignes: 2
        NChiffre: 4 => NLignes: 1
        NChiffre: 3 => NLignes: 1
        NChiffre: 2 => NLignes: 3
        @tri: 2 1 4 3
        On choisi la valeur $max = 2 qui est sur 3 NLignes
        Ce qui reste dans le tableau après shift @tri: 1 4 3
        

        Et je pense que tu peux mettre en résolu.

        0