retrouver un mot dans un Fichier

retrouver un mot dans un Fichier - Perl - Programmation

Marsh Posté le 27-04-2015 à 13:26:25    

Salut je suis un debutant en Perl et je n'ai pas encore de l'experience et j'ai besoin de votre aide.  
 j'ai un fichier contenant des results de traitement de d'autre Fichiers que j'aimerai un peu avoir un bon appercu, au fait dans mon Fichier il ya les resultats suivant:
 
default,primary,secondary,copy_directory,forced_copy_flag,always_allow_dump,type_of_dump,full_memory_dump,
 
d100spuptl25e0,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,1,fault,disallow,
doc1,/del,/dev/null,/ras,1,0,fw-assisted,disallow,
doc2,/dev/lg_dumplv,/dev/sysdumpnull,//ras,1,1,fw,disallow,
doc3,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,fault,fw-assisted,disallow,
doc4[/#FF1C00],5,fault,7,8,9,10,disallow,
 
en rouge ce sont les noms des fichiers, en noir ce sont des valeurs le premier fichier default ne doit pas etre pris en consideration,  seul les autres fichiers doivent etres traite
j'aimerai que les noms des fichier ayant la valeur "fault" me soit retourne, et ainsi que leur nombre. Dans la cas ici present le
resultat serait:
nombre de fichiers: 3
d100spuptl25e0
doc3
doc4
 

Reply

Marsh Posté le 27-04-2015 à 13:26:25   

Reply

Marsh Posté le 27-04-2015 à 14:32:29    

Moi aussi je suis débutant, mon script fonctionne mais gilou (qui s'y connait très bien) aura peut-être des améliorations à proposer. J'ai mis quelque commentaires, si tu ne comprends pas demande moi!

Code :
  1. use strict; #il faut déclarer ses variables
  2. use warnings FATAL => 'all'; #stopper au moindre soucis
  3. use autodie; #stopper si problème sur les fichiers i/o
  4. open(INPUT, '<', 'fichier.txt');
  5. my $nombre=0;
  6. my @fichiers;
  7. while((my $ligne=<INPUT> ))
  8. {
  9.     next if($ligne=~/^\s+$/); #ignorer lignes vides ou contenant seulement des espaces
  10.     next if($ligne=~/^default/); #ignorer la ligne qui commence par "default"
  11.    
  12.     if($ligne=~/,fault,/) #si la ligne contient le mot "fault" entouré de virgules
  13.     {
  14.         $nombre++;
  15.         push @fichiers, (split(/,/, $ligne))[0]; #découper la ligne aux virgules et mettre le premier morceau dans @fichiers
  16.     }
  17. }
  18. close(INPUT);
  19. open(OUTPUT, '>', 'resultat.txt');
  20. print OUTPUT "nombre de fichiers: $nombre\n";
  21. print OUTPUT join("\n", @fichiers); #prendre le contenu de @fichiers, mettre un saut de ligne entre deux éléments et écrire le tout dans le fichier sortie
  22. close(OUTPUT);

Message cité 1 fois
Message édité par rat de combat le 27-04-2015 à 14:53:32
Reply

Marsh Posté le 27-04-2015 à 15:26:16    

Merci bien

Reply

Marsh Posté le 27-04-2015 à 20:41:28    

rat de combat a écrit :

Moi aussi je suis débutant, mon script fonctionne mais gilou (qui s'y connait très bien) aura peut-être des améliorations à proposer.


C'est bien, j'aurais condensé un peu:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. open(my $fhin, '<', 'fichier.txt');
  7. my @fichiers = ();
  8. while (<$fhin> ) {
  9.    push @fichiers, (split(/,/, $_))[0] if (/,fault,/);
  10. }
  11. close($fhin);
  12.  
  13. open(my $fhout, '>', 'resultat.txt');
  14. print $fhout "nombre de fichiers: ", 0+@fichiers, "\n";
  15. print $fhout "$_\n" foreach (@fichiers);
  16. close($fhout);


La seule différence essentielle est que je préfère des filehandle locaux, mais c'est juste une question de style.
 
A+,


Message édité par gilou le 27-04-2015 à 23:20:43

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

Marsh Posté le 27-04-2015 à 21:13:38    

Gilou merci de ta proposition

Reply

Marsh Posté le 27-04-2015 à 22:19:04    

Non, ça c'était juste pour répondre au rongeur combatif.
J'aurais procédé ainsi:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5. use File::Grep qw( fgrep );
  6.  
  7. my @fichiers = fgrep { /,fault,/ } 'fichier.txt';
  8. open(my $fhout, '>', 'resultat.txt');
  9. print $fhout "nombre de fichiers: ", $fichiers[0]->{count}, "\n";
  10. foreach (sort keys %{$fichiers[0]->{matches}}) {
  11.  print $fhout +(split(/,/, $fichiers[0]->{matches}->{$_}))[0], "\n";
  12. }
  13. close $fhout;

:D  
J'aurais utilisé le module File::Grep, qui fait tout le boulot de parsing, et utilisé le fait qu'il retourne une structure qui contient toute l'info utile.
Sur ton exemple, fgrep retourne une liste dont le premier (et unique élément) est une référence sur un hash:
$fichiers[0] = {
          'count' => 3,
          'matches' => {
                         '6' => "doc3,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,fault,fw-assisted,disallow,\n",
                         '3' => "d100spuptl25e0,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,1,fault,disallow,\n",
                         '7' => "doc4,5,fault,7,8,9,10,disallow,\n"
                       },
          'filename' => 'aaz.txt'
        };
 
A+,


Message édité par gilou le 27-04-2015 à 23:20:05

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

Marsh Posté le 27-04-2015 à 22:43:05    

je trouve ta premiere proposition, bonne pour la comprenhesion

Reply

Marsh Posté le 27-04-2015 à 23:15:00    

C'est le principe de Perl: il n'y a pas UNE bonne solution, toute solution adaptée au niveau de celui qui l'utilise est bonne. :)
 
J'aurais pu écrire la mienne ainsi:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5. use File::Grep qw( fgrep );
  6.  
  7. my @fichiers = fgrep { /,fault,/ } 'fichier.txt';
  8. open(my $fhout, '>', 'resultat.txt');
  9. print $fhout "nombre de fichiers: ", $fichiers[0]->{count}, "\n";
  10. print $fhout "$_\n" foreach (map {(split(/,/, $fichiers[0]->{matches}->{$_}))[0]} sort keys %{$fichiers[0]->{matches}});
  11. close($fhout);


 
Mais ça aurait été moins (ou pas) lisible a qui n'est pas un utilisateur avancé.
Le truc utile utilisé ici: si %hash est un hash, map {$hash{$_}} sort keys %hash; renvoie la liste des valeurs du hash, triées dans l'ordre des clés.
 
Tiens, une variante plus simple de mon premier post:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. open(my $fhin, '<', 'fichier.txt');
  7. my @fichiers = grep { /,fault,/ and s/,.*// } (<$fhin> );
  8. close($fhin);
  9.  
  10. open(my $fhout, '>', 'resultat.txt');
  11. print $fhout "nombre de fichiers: ", 0+@fichiers, "\n";
  12. print $fhout "$_" foreach (@fichiers);
  13. close($fhout);


 
Plutôt que de splitter en champs séparés par une virgule, et ne garder que le premier champ je vire tout ce qui après la première virgule (sauf le \n final). C'est probablement plus optimal.
j'aurais pu écrire map { s/,.*//; $_ } grep { /,fault,/ } à la place de grep { /,fault,/ and s/,.*// } pour faire plus pédagogique.
 
A+,


Message édité par gilou le 28-04-2015 à 03:34:14

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

Marsh Posté le 28-04-2015 à 10:58:21    


 exactement ceci et vraiment plus simple,car je dois essaye de comprendre comment est ce que cela fonctionne merci bien

Reply

Marsh Posté le 28-04-2015 à 11:02:27    

mais dit pourquoi 0+@fichiers, le 0 qu'est ce que tu veus dire pas j'aurai imagine scalar @fichiers

Reply

Marsh Posté le 28-04-2015 à 11:02:27   

Reply

Marsh Posté le 28-04-2015 à 11:49:16    

j'avais encore une question comme vous l'avez remarque le resultat du fichier suivant n'ai pas agreable a lire:
 
default,primary,secondary,copy_directory,forced_copy_flag,always_allow_dump,type_of_dump,full_memory_dump,
d100spuptl25e0,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,1,fault,disallow,
doc1,/del,/dev/null,/ras,1,0,fw-assisted,disallow,
doc2,/dev/lg_dumplv,/dev/sysdumpnull,//ras,1,1,fw,disallow,
doc3,/dev/lg_dumplv,/dev/sysdumpnull,/var/adm/ras,1,fault,fw-assisted,disallow,
doc4[/#FF1C00],5,fault,7,8,9,10,disallow,  
 
j'aimerai savoir si il est possible en perl .d'ecrire un code capable d'ecrire cela dans une table html mais ce qui important de savoir est que le Tableau 6 lignes et 8 colonnes ceci peut toujours varie
du genre 4000 ligne et peut etre 200 colonnes. plus bas vous pouvez trouver mon code qui me donne ce resultat peut quelqu'un pourrai savoir ce qu'il faudrai que j'y ajoute. comme je l'ai mensionne le resultat je l'obtient comme en haut j'aimerai savoir si il est posible de l'avoir du genre comme ceci en desous.
 
 
default              primary              secondary              copy_directory     forced_copy_flag   always_allow_dump   type_of_dump   full_memory_dump  
d100spuptl25e0  /dev/lg_dumplv   /dev/sysdumpnull     /var/adm/ras        1                        1                            fault               disallow  
doc1                /del                   /dev/null                /ras                    1                        0                            fw-assisted      disallow  
doc2                /dev/lg_dumplv    /dev/sysdumpnull    //ras                   1                        1                            fw                  disallow  
doc3                /dev/lg_dumplv    /dev/sysdumpnull    /var/adm/ras        1                         fault                       fw-assisted      disallow  
doc4                5                       fault                     7                        8                        9                           10                   disallow  
 

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4. use XML::Twig;
  5. use Text::CSV;
  6. use Text::xSV;
  7. my $file1 = shift @ARGV;                                   
  8. my @files = glob '*.xml';                                   
  9. @files = grep { $_ ne $file1 } @files if defined $file1; 
  10. my $FileResult = 'result.csv'; 
  11. open( my $FhResult, '>', $FileResult )or die ("Unable to open file $FileResult\n$!" );
  12. my $twig1= XML::Twig->new(   
  13.         twig_handlers => { 
  14.                 'Parameter' => sub { 
  15.                         my $attr_name = $_->{'att'}->{'name'} // 'fault';   
  16.                     
  17.                                                       
  18.                         print $FhResult $attr_name . ",";   
  19.                 },
  20.         },
  21. );
  22. print $FhResult( (split('_', $file1,2))[0] . ',' ); 
  23. $twig1->parsefile($file1); 
  24. for my $file (@files) {
  25.     my $twig1 = XML::Twig->new(
  26.         twig_handlers => {
  27.             'Parameter' => sub {
  28.                 my $attr_value = $_->{'att'}->{'value'} // 'fault';   
  29.                 print $FhResult $attr_value . ",";
  30.             },
  31.         },
  32.     );
  33.     print $FhResult ( split( '_', "\n$file", 2 ) )[0] . ',';
  34.     $twig1->parsefile($file);                                     
  35. }
  36. close $FhResult;

Reply

Marsh Posté le 28-04-2015 à 11:51:40    

Henri772 a écrit :

mais dit pourquoi 0+@fichiers, le 0 qu'est ce que tu veus dire pas j'aurai imagine scalar @fichiers

La variable @fichiers est une liste. Si j'appelle print dessus, ça va imprimer le contenu de la liste.
Je veux forcer une interprétation scalaire de la variable, ce qui me donnera son nombre d'éléments.
Je pourrais en effet utiliser l'opérateur unaire scalar de perl, et écrire scalar @fichiers, mais dans la pratique, on utilise souvent l'idiome 0+@fichiers, l'addition d'un nombre forçant l'interprétation scalaire de @fichiers. Je suppose que cette pratique provient des temps reculés ou l'opérateur scalar n'existait pas dans le langage.
J'aurais aussi pu faire $#fichiers + 1.
C'est juste une question d'habitude.
 
A+,


Message édité par gilou le 28-04-2015 à 11:52:16

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

Marsh Posté le 28-04-2015 à 12:08:48    

Henri772 a écrit :

j'aimerai savoir si il est possible en perl .d'ecrire un code capable d'ecrire cela dans une table html mais ce qui important de savoir est que le Tableau 6 lignes et 8 colonnes ceci peut toujours varie du genre 4000 ligne et peut etre 200 colonnes. plus bas vous pouvez trouver mon code qui me donne ce resultat peut quelqu'un pourrai savoir ce qu'il faudrai que j'y ajoute. comme je l'ai mensionne le resultat je l'obtient comme en haut j'aimerai savoir si il est posible de l'avoir du genre comme ceci en desous.

C'est pas très clair ton histoire.
 
A+,


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

Marsh Posté le 28-04-2015 à 13:15:18    

Gilou ilmalheureusement impossible des poste l'un des fichiers donc je possede sur le forum la tu allais faire la remaque que un Fichier en possede des milliers d'attributs value, et par ailleur si on parse un tel fichier, ceci n'ai pas agreable pour l'oeil de pouvoir lire le resultat car, il apparaitra des nombre et caractere separe de virgule.

Reply

Marsh Posté le 28-04-2015 à 13:40:41    

CE qui n'est pas clair, c'est ce que tu veux obtenir au final.
Une table html? une fichier texte séparé par des tabulations? etc.
 
Si c'est pour une table html, je te suggère d'aller voir du côté de  HTML::Table::Compiler qui est très pratique pour remplir une table avec une liste de valeurs.
 
A+,


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

Marsh Posté le 29-04-2015 à 21:47:26    

Merci gilou pour la relecture de mon code! Bien vu qu'il ne faut pas de variable en plus pour compter le nombre de fichiers. Et je note le coup du 0+@fichiers qui est plus court que scalar() que j'utilise habituellement.

Reply

Sujets relatifs:

Leave a Replay

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