[Perl] Arrêt traitement si doublons dans champ d'un fichier

Arrêt traitement si doublons dans champ d'un fichier [Perl] - Perl - Programmation

Marsh Posté le 02-02-2017 à 17:02:22    

Bonjour,
 
Je m'arrache les cheveux sur mon problème.
 
J'ai bien essayé d'adapter la solution du topic : http://forum.hardware.fr/hfr/Progr [...] 5185_1.htm mais je n'y arrive pas.
 
Voila mon problème.
 
J'ai un fichier sous la forme :
 
cmd1 param1 valeur1
cmd2 param2 valeur2
...
 
Les champs cmd et valeur peuvent être identique mais pas le champ param qui doit être unique.
 
Avant de faire mon traitement je veux donc analyser mon fichier pour contrôler que je n'ai pas deux fois la même valeur dans le champ param.
Si c'est le cas il faut que j'arrêt la.
 
Par exemple si mon fichier est le suivant :
 
cmd1 param1 valeur1
cmd2 param2 valeur2
cmd3 param1 valeur3
cmd1 param3 valeur4
cmd2 param2 valeur5
cmd4 param4 valeur6
cmd5 param2 valeur7
 
Je dois sortir en précisant que le param1 a été trouvé 2 fois et que le param2 à été trouvé 3 fois.
 
Voila ce que j'ai essayé de faire :
 

Code :
  1. open(F, 'cmd.txt') || die "Problème à l\'ouverture : $!";
  2. my $num_cmd = 0;
  3. while(<F> )
  4. {
  5. push @cmd,$_;
  6. $num_cmd ++;
  7. }
  8. close F || die "Problème à la fermeture : $!";
  9. ########################################################
  10. # compte le nombre de fois ou le paramètre est présent #
  11. ########################################################
  12. my %myhash;
  13. my @parsed;
  14. my $arret=0;
  15. my $h=0;
  16. foreach (@cmd)
  17. {
  18. @parsed = split /\s*\ \s*/, $_;
  19. $myhash{$parsed[1]}++;
  20. }
  21. foreach (sort {$myhash{$b} <=> $myhash{$a}} (keys(%myhash)))
  22. {
  23. m/([^.]+)\.(.*)/;
  24. if ($myhash{$_} != 1)
  25. {
  26.  print LOG "Une action sur $2 est present $myhash{$_} fois\n";
  27.  $arret=1;
  28. }
  29. }
  30. ####################################################
  31. # arrêt si le paramètre est présent plusieurs fois #
  32. ####################################################
  33. if ($arret == 1)
  34. {
  35. print LOG "ARRET de l'update\n";
  36. print "Probleme UPDATE non fait, voir la log\n";
  37. exit;
  38. }


 
Ca fonctionne sauf que j'ai le message suivant :
Use of uninitialized value in concatenation (.) or string at E:\Outils\update\maj.pl line 114.
Use of uninitialized value in concatenation (.) or string at E:\Outils\update\maj.pl line 114.
Probleme UPDATE non fait, voir la log
 
Et dans mon fichier de LOG :
 
Une action sur  est present 2 fois
Une action sur  est present 3 fois
ARRET de l'update
 
Merci de votre aide :jap:
 
 
 
 
 

Reply

Marsh Posté le 02-02-2017 à 17:02:22   

Reply

Marsh Posté le 02-02-2017 à 23:58:28    

Donc un truc dans ce gout ci:

Code :
  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. my %params;
  7.  
  8. open(my $fh, '<', 'cmd.txt');
  9. while (<$fh> ) {
  10.    $params{$1}++ if (/^\s*(?:\S+)\s+(\S+)\s+(?:\S+)\s*$/);
  11. }
  12. close($fh);
  13.  
  14. # classement par nb de fois
  15. foreach (sort {$params{$b} <=> $params{$a}} (keys(%params))) {
  16.    if ($params{$_} > 1) {
  17.     print "le $_ a ete trouve $params{$_} fois\n";
  18.    }
  19. }


Et pour classer par nom de param, il suffit de virer le {$params{$b} <=> $params{$a}} devant sort.
 
Et pour une version bien organisee permettant une sortie sans passer par un appel a exit:

Code :
  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. my %params;
  7.  
  8. open(my $fh, '<', 'cmd.txt');
  9. while (<$fh> ) {
  10.    $params{$1}++ if (/^\s*(?:\S+)\s+(\S+)\s+(?:\S+)\s*$/);
  11. }
  12. close($fh);
  13.  
  14. foreach (keys(%params)) {
  15.    delete $params{$_} if ($params{$_} < 2);
  16. }
  17.  
  18. if (%params) {
  19.    # classement par nb de fois
  20.    foreach (sort {$params{$b} <=> $params{$a}} (keys(%params))){
  21.        print "le $_ a ete trouve $params{$_} fois\n";
  22.    }
  23.    # message de fin de traitement, en erreur
  24. }
  25. else {
  26.    # proceder au traitement
  27. }


 
A+,


Message édité par gilou le 03-02-2017 à 00:38:07

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

Marsh Posté le 03-02-2017 à 11:06:36    

Bonjour,
 
Merci beaucoup Gilou :) ça fonctionne très bien.  :bounce:  
 
J'ai juste oublié de préciser une petite chose, mais elle est importante.
Il n'y a pas forcément de champ valeur et dans ce cas ça ne fonctionne plus.
 
J'essaie de comprendre ce que tu as fais, mais je ne trouve pas la solution si le champ valeur est absent.
 
 :jap:

Reply

Marsh Posté le 04-02-2017 à 11:27:06    

Bonjour, s'il n'y a pas de champ valeur, ça simplifie les choses:
/^\s*\S+\s+(\S+)/
On ne parse plus que les deux champs obligatoires en début de ligne.
(bon, on pouvait déjà aussi faire comme ça avant, parser la ligne complète permettait juste de s'assurer qu'on ne parsait que les lignes a trois champs obligatoires).
 
A+,


Message édité par gilou le 04-02-2017 à 11:44:10

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

Marsh Posté le 06-02-2017 à 10:37:54    

Bonjour,
 
Encore une fois un grand merci Gilou ça fonctionne parfaitement.
Si je peux me permettre peux tu m'expliquer la regex /^\s*\S+\s+(\S+)/ ?
 
:jap:

Reply

Marsh Posté le 06-02-2017 à 13:27:23    

Tu peux utiliser ce site pour tester/expliquer des regexp, c'est très pratique.
https://regex101.com/


---------------
sheep++
Reply

Marsh Posté le 06-02-2017 à 13:40:17    

:jap:

Reply

Marsh Posté le 06-02-2017 à 17:34:46    

/
^      Debut de ligne suivi de  
\s*    Blancs (SPACE ou TAB) optionnels en debut de ligne suivis de  
\S+    un ou plusieurs caracteres differents de space et TAB  (\S c'est le contraire de \s)
\s+    un ou plusieurs blancs  
(\S+) un ou plusieurs caracteres differents de space et TAB copies dans groupe (donc $1)
/  
Comme on est en mode greedy (on matche le plus grand nombre de caractères possibles), on sait que (\S+) va capturer tous les caractères jusqu’à ce qu'il rencontre un SPACE, TAB ou la fin de la ligne.
 
A+,


Message édité par gilou le 06-02-2017 à 17:40:06

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

Marsh Posté le 07-02-2017 à 15:40:18    

Milles Merci.
 
:jap:
 
Maintenant je dois faire la même chose en java :(
J'ouvre un autre Topic :bounce:

Reply

Sujets relatifs:

Leave a Replay

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