[PERL] Extraire le contenu d'un fichier [Fermé]

Signaler
-
 cramer -
Bonjour,

La question que je vous pose a déjà été posé, mais il semblerait que les solutions apportées ne fonctionnent pas chez moi. Je précise quand même que je débute en perl.

Alors voilà, j'ai le fichier suivant :
.................
<cre>
.......................
<type_msg>103</type_msg>
..............
</cre>
................

La balise <cre></cre> peut se répeter indéfiniment et je voudrais extraire dans des fichiers séparés l'ensemble de la balise <cre></cre> en fonction de type_msg, pouvant prendre les valeurs 103,202 ou 204.
Je ne sait pas si celà est important, mais il peut y avoir des espaces, tabulations,sauts de lignes entre les balises.

J'ai donc à partir des réponses du forum fait ceci :

#! /usr/bin/perl

use warnings;use strict;
undef $/;
my $fic = <>;
chomp;
pos($fic)=0;
open(DEST1, ">103.txt");
open(DEST2, ">202.txt");
open(DEST3, ">204.txt");

while ( $fic =~ m/<cre>/gmc ){
print "Lecture du Fichier : \n";
if ($fic =~ / \G(.*?<type_msg>103.*?<\/cre>)/){
print "MT103\n";
print DEST1 $1;
}
if ($fic =~ / \G(.*<type_msg\>202.*<\/cre>)/){
print "MT202\n";
print DEST2 $1;
}
if ($fic =~ / \G(.*<type_msg>204.*<\/cre>)/){
print "MT204\n";
print DEST3 $1;
}

}

close($fic);
close(DEST1);
close(DEST2);
close(DEST3);


mais celà ne fonctionne pas. Il semblerait que le soucis soit au niveau des tests. Pourriez vous m'aider ?

Merci d'avance.

12 réponses

il semblerait que l'affichage dans "\G" affiche une ',' au lieu d'un point.
Messages postés
23763
Date d'inscription
dimanche 26 août 2001
Statut
Modérateur
Dernière intervention
13 janvier 2020
3 087
Salut,

un truc m'échappe : tu es obligé de conserver les données que tu as déjà lues pour les mettre dans le bon fichier, vu que la balise type_msg n'est présente qu'au milieu de la balise cre, comment fais-tu ?
Bonjour,

oui je suis obligé de conserver les données déjà lues, puisque l'interieur des balises varie en fonction du type_msg. Celà me permet de rediriger tous les 103 dans un fichier, puis de les traiter avec un parser, idem avec les 202 et 204.


while ( $fic =~ m/<cre>/gmc ){
print "Lecture du Fichier : \n";
if ($fic =~ / \G(.*?<type_msg>103.*?<\/cre>)/){


Pour répondre à ton autre question, justement je ne suis pas sûr que celà soit bon, mais voici pourquoi j'ai fait cà :

while ( $fic =~ m/<cre>/gmc ){
print "Lecture du Fichier : \n";
if ($fic =~ / \G(.*?<type_msg>103.*?<\/cre>)/){


"m/ ... /gmc", me fait une recherche global dans tous le fichier et multiligne. \G (assertion) me permet de recuperer ce qui commence par
<cre> et finit par ".*?<type_msg>103.*?</cre>" et de le rediriger. La position est sauvegardé, et on continue le traitement du fichier en recommencant à la balise <cre> suivante.
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 544
Salut,

met ton fichier sur cjoint.com et je vais regarder ce soir
D'accord merci.

Je ne pourrais le mettre que ce soir, étant au travail, cette URL est bloquée :)
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 544
Salut,

essai comme ça
#!/usr/bin/perl
use strict;use warnings;

open LIRE,"ton_fichier"
  or die "E/S : $!\n";

my (@fic,@res);

while(<LIRE>){
  push @fic,$_ if /<cre>/ .. /<\/cre>/;
}

@res = split /<\/cre>/, join "",@fic;
pop @res;
foreach (@res){
  $_ =~ />(\d{3})</;
  open ECRIRE,">>$1.txt" or die "E/S : $!\n" if $1;
  print ECRIRE "$_</cre>" if $1;
  close ECRIRE;
}

__END__
D'accord je vais essayer. Merci.

Voici le fichier original :
https://www.cjoint.com/?mku712a8jR
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 544
Ce n'est pas le script que j'ai besoin, mais le fichier à traiter ;-)
Impressionnant :)

Celà fonctionne nickel. Je vais tâcher de comprendre cà :)
Mais de visu si je décide que tout ce qui n'est pas 103,202,204 soit dans un fichier IND, il faut qu'après "$_ =~ />(\d{3})</;"
je fasse un test comme cà : (débutant en perl, je ne suis pas sur que

foreach (@res){
$_ =~ />(\d{3})</;
if($1 != '103' || $1!='202' || $1!='204')
{
open ECRIRE, ">>IND.txt" or die "E/S : $!\n" if $1;
print ECRIRE "$_</cre>" if $1;
}
else
{
open ECRIRE,">>$1.txt" or die "E/S : $!\n" if $1;
print ECRIRE "$_</cre>" if $1;
close ECRIRE;
}
}
Messages postés
23763
Date d'inscription
dimanche 26 août 2001
Statut
Modérateur
Dernière intervention
13 janvier 2020
3 087
Fais gaffe, lami20j est redoutable quand il faut de la syntaxe qu'on dirait un tirage des chiffres et des lettres... :-)
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 544 >
Messages postés
23763
Date d'inscription
dimanche 26 août 2001
Statut
Modérateur
Dernière intervention
13 janvier 2020

;-))
Arf celà va être plus compliqué :( Bon, je vais tâcher de t'en créer un vite fait. Le voici :

https://www.cjoint.com/?mkvptvBPUD

C'est loin d'être le fichier original (le fichier XML original est au taf).
Voici un exemple plus sophistiqué :

https://www.cjoint.com/?mkvAcaaQA7
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 544
#!/usr/bin/perl
use strict;use warnings;

open LIRE,"toto.txt"
  or die "E/S : $!\n";

my (@fic,@res);

while(<LIRE>){
  push @fic,$_ if /<cre>/ .. /<\/cre>/;
}

@res = split /<\/cre>/, join "",@fic;
pop @res;
foreach (@res){
  $_ =~ />(\d{3})</;
  if ($1 eq 103 || $1 eq 202 || $1 eq 204){
          open ECRIRE,">>$1.txt" or die "E/S : $!\n" if $1;
          print ECRIRE "$_</cre>" if $1;
  } else {
          open IND,">>IND.txt" or die "E/S : $!\n" if $1;
          print IND "$_</cre>" if $1;
  }
  close IND;
  close ECRIRE;
}

__END__
ou encore
#!/usr/bin/perl
use strict;use warnings;

open LIRE,"toto.txt"
  or die "E/S : $!\n";

my (@fic,@res);

while(<LIRE>){
  push @fic,$_ if /<cre>/ .. /<\/cre>/;
}

@res = split /<\/cre>/, join "",@fic;
pop @res;
foreach (@res){
  $_ =~ />(\d{3})</;
  if ($1 =~ /(103|20[24])/){
          open ECRIRE,">>$1.txt" or die "E/S : $!\n" if $1;
          print ECRIRE "$_</cre>" if $1;
  } else {
          open IND,">>IND.txt" or die "E/S : $!\n" if $1;
          print IND "$_</cre>" if $1;
  }
  close IND;
  close ECRIRE;
}

__END__
Merci à toi lami20j. Tu me tire une belle épingle du pied.