PERL

Résolu
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   -  
lami20j Messages postés 21331 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
A voir également:

18 réponses

lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
:D Ca fonctionne !!!!!!!!!!!!!
Merci. Il ne me reste plus qu'à comprendre ton programme ...
0
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
Je remonte le post ...
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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

Vous n’avez pas trouvé la réponse que vous recherchez ?

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

Par exemple si la valeur est 10 fois supérieur aux autres valeurs,
Je ne comprends pas ;-(
0
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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
xav3601 Messages postés 3289 Date d'inscription   Statut Membre Dernière intervention   311
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570 > wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention  
 
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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570 > wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention  
 
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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570 > lami20j Messages postés 21331 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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2 > lami20j Messages postés 21331 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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
Merci lami20j, j'avais pas vu tes messages. Je suis partie sur la piste de xav3601 mais toujours avec des difficultés ....
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Re,

Tu ne dis en revanche si ça te conviens ce que je t'ai donné.
0
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
C'est en phase de test, je te dis ca dans qq'minutes ;)
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
Oui c'est bien cela
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   2
 
Jusqu'à 30 lignes
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
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
wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention   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
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570 > wafa_o Messages postés 109 Date d'inscription   Statut Membre Dernière intervention  
 
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