Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
3114 connectés 

  FORUM HardWare.fr
  Programmation
  Perl

  trier un fichier texte

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

trier un fichier texte

n°2126643
furil
Posté le 15-02-2012 à 15:56:36  profilanswer
 

Bonjour,
 
Voilà je cherche à trier un fichier texte et je bloque sur la méthode split où l'erreur m'indique que celle-ci n'est pas initialisé. J'ai effectivement oublier de l'initialiser j'ai donc suivi à la lettre mais la même erreur revient :
 

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. system("rrdtool fetch /var/lib/centreon/metrics/50.rrd AVERAGE --start \$\(date -d\'01 january 2012' +%s ) --end \$\( date -d\'31 January 2012\' +%s) > 50.txt" );
  5. #-------Ouverture du fichier contenant les données renvoyées par rrdfetch()
  6. my $cpt = 0;
  7. my @tabtab =();
  8. my @tabtab2 = ();
  9. my $linelement;
  10. my $word = "nan";
  11. open(FF,"50.txt" );
  12.         while(my $line = <FF> )
  13.          {
  14. #si la ligne que je parcours ne comporte pas ce mot je l'ajoute
  15. # "i" permettant de ne pas faire de distinction entre majuscule et minuscule
  16.                  if ($line !~ /$word/i)
  17.                 {
  18.                  push(@tabtab,$line);
  19. $cpt = $cpt + 1;
  20.                 }
  21.          }
  22. close FF;
  23. print $cpt;
  24. foreach $linelement(@tabtab) {
  25.        my ($datetimestamp, $data) = split( ":", $linelement);
  26.         open(FILE,">test.txt" );
  27. #       print $data;
  28.         print FILE $data;
  29.         close FILE;
  30. }


 
 
 
Le fichier texte est composé d'a peu prés 4000 lignes de cette forme :
 
1328051100: 5.5884907200e+06
 
La partie gauche c'est du timestamp, c'est l'autre partie qui m'intéresse, le fichier texte comportait des lignes avec un mot clé qui indiquait qu'elle ne comportait pas de valeur, j'ai donc copié uniquement celle qui comportaient une valeur dans mon tableau.  
Ensuite je cherche a séparé ces 2 valeurs par la méthode split mais c'est là que survient le problème.
En faite, je cherche a écrire uniquement la partie $data qui contient 5.5884907200e+06 (par exemple), dans un autre fichier texte.
Pour au final faire une moyenne de toutes ces valeurs contenu dans $data arrondie à 10^-2 .


Message édité par furil le 15-02-2012 à 16:14:30
mood
Publicité
Posté le 15-02-2012 à 15:56:36  profilanswer
 

n°2126662
gilou
Modérateur
Modzilla
Posté le 15-02-2012 à 17:01:57  profilanswer
 

Pour ta moyenne, ceci devrait coller:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. system("rrdtool fetch /var/lib/centreon/metrics/50.rrd AVERAGE --start \$\(date -d\'01 january 2012' +%s ) --end \$\( date -d\'31 January 2012\' +%s) > 50.txt" );
  6. #-------Ouverture du fichier contenant les données renvoyées par rrdfetch()
  7.  
  8. my $word = "nan";
  9. my $num = 0;
  10. my $cpt = 0;
  11.  
  12. open(FF,"<50.txt" );
  13. map {s/\s*\n$//;; s/^\d+:\s*//; if ($_) {$num += $_; ++$cpt;}} grep !/$word/io, <FF>;
  14. close FF;
  15.  
  16.  
  17. if ($cpt) {
  18.  printf "%e\n", $num/$cpt;
  19. }
  20. else {
  21.  printf "Aucune ligne trouvee\n"
  22. }

Testé sur un fichier 50.txt comme ceci:

1328051100: 5.5884907200e+06  
1328051100: 5.5894907200e+06  
1328051100: nan
1328051100: 5.5874907200e+06  
1328051100: nan  
1328051100: 5.5864907200e+06  
 

C:\Perl>perl test.pl
5.587991e+006


Je suis absent pour 1 à 2h, mais je mettrais qques explications ensuite si nécessaire.
 
A+,


Message édité par gilou le 15-02-2012 à 17:04:04

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2126698
gilou
Modérateur
Modzilla
Posté le 15-02-2012 à 18:05:20  profilanswer
 

map {s/\s*\n$//;; s/^\d+:\s*//; if ($_) {$num += $_; ++$cpt;}} grep !/$word/io, <FF>;


1) grep !/$word/io, <FF>;
ça fait un grep sur le fichier et retourne les lignes ne contenant pas $word. ça retourne ces lignes comme un array
2) map {s/\s*\n$//;; s/^\d+:\s*//; if ($_) {$num += $_; ++$cpt;}} (@lignes)
ça applique {s/\s*\n$//;; s/^\d+:\s*//; if ($_) {$num += $_; ++$cpt;}} à chaque ligne
3) {{s/\s*\n$//;; s/^\d+:\s*//; if ($_) {$num += $_; ++$cpt;}}if ($_) {$num += $_; ++$cpt;}}
Ça vire ce qui est inutile a chaque extrémité: s/\s*\n$//;; s/^\d+:\s*//;
s'il reste qque chose dans la ligne courante $_, ça doit être la chaine contenant les caractères du nombre (et rien de plus), perl le convertit directement en un nombre si je l'utilise en contexte numérique (avec une addition ici).  
Donc si j'ai trouvé un nombre restant a ajouter à ma moyenne, je l'ajoute, et j'augmente le nombre de nombres ajoutés à la moyenne: if ($_) {$num += $_; ++$cpt;}
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2126776
furil
Posté le 16-02-2012 à 10:27:50  profilanswer
 

Bonjour Gilou,
 
Encore merci, j'avance plus vite grâce à toi.  :)  
 
Ensuite au niveau de l'ensemble j'ai compris ce que fait le script mais :
 

Code :
  1. {s/\s*\n$//;; s/^\d+:\s*//;


 
J'ai compris l'explication générale, j'ai même refait quelques script avec cette fonction en utilisant \w+ (...)
Mais serait-il possible que tu me détaille cette ligne  car j'avoue que si on me demande d'expliquer au détail, je ne saurais pas comment m'y prendre  :ange:  
 
Enfin le résultat est certes bon mais je n'arrive pas à le convertir en décimal, plus précisement à deux chiffres aprés la virgule avec %0.2f j'obtiens le résultat suivant :
 
5261226.49 alors que je veux 5.26
 
Merci d'avance et bonne journée


Message édité par furil le 16-02-2012 à 11:20:10
n°2126792
gilou
Modérateur
Modzilla
Posté le 16-02-2012 à 11:46:58  profilanswer
 

{s/\s*\n$//; s/^\d+:\s*//; (il y avait un ; inutile après un premier ;)
c'est  
1) s/\s*\n$//;  
Un classique: on nettoie la fin de ligne
On vire les espaces éventuels (\s espace \s* espaces éventuels) suivis d'un caractère de fin de ligne (\n) en fin de ligne ($)
s/toto// ça remplace (une fois) toto par rien, donc ça le vire, dans la variable $_ qui contient la ligne courante
car, map { blabla } @toto; c'est la même chose que foreach (@toto) {blabla;} qui assigne chaque ligne du tableau @toto à $_
L'avantage de map que j'utilise ici, c'est que comme le tableau arrive après le bloc, on peut y substituer un truc complexe en fin de ligne, alors que ça serait lourd avec un foreach.
2) s/^\d+:\s*//
la aussi, clairement c'est du nettoyage, puisqu'on a // en fin d'expression:
on vire ce qui est en début de ligne (^), qui est constitué d'une suite de chiffres suivis d'un : (\d+:) suivi éventuellement de blancs (\s*)
Bref cette partie vire ce qui est avant le 5.5884907200e+06 d'une ligne 1328051100: 5.5884907200e+06  
tandis que l'autre vire ce qui est après le 5.5884907200e+06 d'une ligne 1328051100: 5.5884907200e+06    (on le voit pas mais il y a du blanc)
Donc au final, les deux ne laissent que la partie 5.5884907200e+06 d'une ligne 1328051100: 5.5884907200e+06  et c'est ce qu'il faut à perl pour qu'il puisse l'interpréter comme un nombre (du blanc avant ou après ferait échouer cela).
 
A+,


Message édité par gilou le 16-02-2012 à 12:01:13

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2126793
furil
Posté le 16-02-2012 à 11:59:54  profilanswer
 

Rapide, clair, efficace. :D
 
Merci j'ai compris le principe et pour le ";" je me disais aussi  :lol:  
 
Bonne journée.

n°2126794
gilou
Modérateur
Modzilla
Posté le 16-02-2012 à 12:01:24  profilanswer
 

Citation :

Enfin le résultat est certes bon mais je n'arrive pas à le convertir en décimal, plus précisement à deux chiffres aprés la virgule avec %0.2f j'obtiens le résultat suivant :  
 5261226.49 alors que je veux 5.26

Comme tu as pu voir sur mon exemple, c'est %.2e et non pas %.2f qu'il faut utiliser
Par contre on ne peut pas contrôler avec (s)printf le nombre de chiffres de l'exposant (2 ou 3).
Bon, il y a toujours moyen de mettre ça dans une chaîne sur laquelle on fait s/\+00/+0/ avant d'afficher la chaine.
  my $a = sprintf "%0.2e\n", $num/$cpt;
  $a =~ s/\+00/+0/;
  print $a;
 
A+,


Message édité par gilou le 16-02-2012 à 12:11:40

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

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Perl

  trier un fichier texte

 

Sujets relatifs
Script batch vérification fichier txttrier des données dynamiques dans Excel
Comment peut on instancier un fichier .cs??Ouvrir fichier avec filename avec accents
Lecture et recopie d'une matrice depuis un fichier texte[bash] ajouter le résultat d'une commande à une ligne dans un fichier
Problèmes - Logiciel d'acquisition de tempsModifier partage groupe résidentiel d'un fichier
Windows Search et Metadonnée d'un fichier : figé ou pas ?fichier texte ouvert avec fgetcsv() en php (résolu)
Plus de sujets relatifs à : trier un fichier texte


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR