[Perl] extraction de chaine

extraction de chaine [Perl] - Perl - Programmation

Marsh Posté le 21-01-2005 à 09:37:51    

Bonjour,
 
Je cherche une expression reguliere qui puisse ranger dans une variable, une chaine de caractere qui se trouve entre 2 chaines.
 
ex :
 
Probleme Description:
Tout est planter(test)
 
Resolution.
 
j'ai esseyer ça:
 

Code :
  1. push @description, $1 if /Probleme Description\s+(.+)^/


 
mais ça marche pas ça ne va pas chercher a la ligne suivante.
Si quelqu'un connaissai l'astuce, ça me serai grandement utile.
 
Merci.

Reply

Marsh Posté le 21-01-2005 à 09:37:51   

Reply

Marsh Posté le 23-01-2005 à 11:50:01    

Fait un tr/\n\r//d; sur la ligne précédente et ca devrait marcher normalement...
 
push @description,$2 if m/^(Probleme Description\s+)(.+?)(\s+Resolution)/;


---------------
Mon Flickr
Reply

Marsh Posté le 24-01-2005 à 13:54:34    

je te remercie de ta reponse mais ça n'a pas l'air de marcher   :(

Reply

Marsh Posté le 24-01-2005 à 20:12:27    

perl -e 'local $/; $_=<>; /^Probleme Description:(.*)^Resolution/ms; print $1'


 
Le //s permet de traiter les chaines multi-lignes comme une seule ligne. Le //m permet de faire matcher ^ et $ avec les debut de ligne et fin de ligne, au lieu des debut de chaine et fin de chaine.


Message édité par matafan le 24-01-2005 à 20:13:04
Reply

Marsh Posté le 25-01-2005 à 09:46:37    

Ha je te remercie grandement pour ton aide ça marche.
 
Par contre je comprend pas bien le

Code :
  1. local $/

et le

Code :
  1. $_=<>


 
Pourrai tu m'éclairer là dessus?
Merci.

Reply

Marsh Posté le 25-01-2005 à 10:33:53    

$/ est une variable speciale qui indique à Perl le separateur de ligne à utiliser kand il lit un fichier.
En temps normal il vaut \n (ou \r\n).
 
<> est l'entrée standard (clavier), ca equivaut à <STDIN>, ca lit donc l'entrée standar en s'arrettant à chaque ligne... enfin à chaque fois qu'il rencontre la valeur de $/.
Dans ce cas precis $/ a été "effacé" (local redefini la variable dans le scope, et comme rien ne lui est assigné elle vaut undef), et plus rtien n'arrettera donc la lecture (sauf un fin de fichier, ou un ctrl-Z dans le cas de l'entrée standard).
on utilise souvent cette technique pour "slurper" un fichier d'un seul coup dans une variable:
 

Code :
  1. my $fichier = do{
  2.   local $/=undef; # ou local $/ tout court
  3.   <IN>;
  4. }


 
ou met tout ca dans un bloc (ou ici un do{}) pour ne pas modifier la valeur de $/ dans le reste du script (et dans les modules). c'est tres important car ca peut affecter d'autres parties du code. donc jamis de "$/=undef" sans "local" et sans bloc autour!
 
Sinon... dans ce cas precis $/ et <> ne servait qu'à illustrer le fonctionnement de la regexp...


Message édité par pospos le 25-01-2005 à 10:34:16
Reply

Marsh Posté le 25-01-2005 à 10:46:30    

Merci pour ta réponse.
 
dans mon cas vu que je veux recupéré d'autre chaine de caractere, j'ajoute  dans ma boucle while qui lit mon fichier
 

Code :
  1. push @description, $1 if /^Problem Description:(.*)^Problem Resolution/ms;
  2. push @call, $1 if /Help Desk Call\s+(.+)$/;

 
 
avec la derniere ligne là je veux extraire ce qu'il y a derriere "Help Desk Call" (il s'agit d'un numero).
Cette expression reguliere fonctionne, je l'ai tester plusieur fois.
Mais quand je l'insere dans la boucle et que je fait un "print @call", cela ne m'ffiche rien du tout.

Reply

Marsh Posté le 25-01-2005 à 10:51:11    

ha...
si tu lit ton fichier dans une boucle sans avoir modifié la variable $/ il va le lire ligne par ligne... et donc tu ne pourra pas utiliser ta regexp...
la solution consiste à avoir ton fichier ENTIER dans une variable, et d'appliquer ensuite ta regexp dessus. Pour faire ca soit tu concatene ta variable dans ta boucle while puis tu match ensuite, soit tu fais comme indiqué au dessus. Par exemple un petite fonction que j'utilise souvent:
 

Code :
  1. my $a = slurp("blabla.txt" );
  2. $a =~ ....
  3. sub slurp {
  4. my $file = shift;
  5. my $fh;
  6. if (UNIVERSAL::isa($file, 'GLOB')) {
  7.  $fh = $file;
  8. } else {
  9.  open($fh, '<', $file) || return undef;
  10. }
  11. binmode $fh;
  12. if (wantarray) {
  13.  <$fh>
  14. } else {
  15.  local $/;
  16.  <$fh>
  17. }
  18. <$fh>
  19. }


Message édité par pospos le 25-01-2005 à 11:31:20
Reply

Marsh Posté le 25-01-2005 à 11:11:57    

Houla j'ai pas tout compris  :??:  
 
voila mon code :
 

Code :
  1. #!/usr/bin/perl -w
  2. use strict;
  3. my ( @call, @description, @resolution, @id1, @id2, $fav, $ligne );
  4. $fav = "toto1.txt";
  5. open AVANT, $fav or die "Impossible d'ouvrir $fav\n";
  6. local $/;
  7.     while (<AVANT> )
  8.         {
  9.         #Recherche du numero de la demande
  10.         push @call, $1 if /Help Desk Call\s+(.+)$/ ;
  11.         #Recherche de la description de la demande
  12.         push @description, $1 if /^Problem Description:(.*)^Problem Resolution/ms;
  13.         #Recherche de la resolution de la demande
  14.         push @resolution, $1 if /^Problem Resolution:(.*)^Opened By/ms;
  15.         #Recherche de l'id1
  16.         push @id1, $1 if /Opened By\s+(.+)$/ ;
  17.         #Recherche de l'id2
  18.         push @id2, $1 if /Sent To\s+(.+)$/ ;
  19.         }
  20.         print ("\nObjet : Enregistrement de la demande numero @call \n" );
  21.         print ("\nDescription de la demande: @description \n" ) ;
  22.         print ("Description de la resolution: @resolution \n" );
  23.         print ("\nOuvert par:   @id1 \n" );
  24.         print ("Envoye a:       @id2 \n\n" );
  25. close AVANT;


 
ça ne me renvoie ni @call, ni @id1
 
mon fichier toto1.txt se presente comme ça :
 

Code :
  1. Objet : Event Notification For: Help Desk Call #20378
  2. Problem Description:
  3. Tout est planter (test)
  4. Problem Resolution:
  5. Plus rien n'est plante
  6. Opened By               JD: Dupont, Jean
  7. Sent To                 IN: inconnu


 
Si tu pouvais m'aider ça serai sympa, ça fait 3 semaines que je galere dessus  :(

Reply

Marsh Posté le 25-01-2005 à 11:43:28    

Code :
  1. use strict;
  2. $_ = slurp("toto1.txt" );
  3. #Recherche du numero de la demande
  4. my ($call) =  /Help Desk Call\s+([^\r\n]*)/ ;
  5. #Recherche de la description de la demande
  6. my ($description) = /Problem Description:(.*?)Problem Resolution:/ms;
  7. #Recherche de la resolution de la demande
  8. my ($resolution) = /^Problem Resolution:(.*?)Opened By/ms;
  9. #Recherche de l'id1
  10. my ($id1) = /Opened By\s+([^\r\n]*)/;
  11. #Recherche de l'id2
  12. my ($id2) = /Sent To\s+([^\r\n]*)/;
  13. print ("\nObjet : Enregistrement de la demande numero $call \n" );
  14. print ("\nDescription de la demande: $description \n" ) ;
  15. print ("Description de la resolution: $resolution \n" );
  16. print ("\nOuvert par:   $id1 \n" );
  17. print ("Envoye a:       $id2 \n\n" );
  18. sub slurp {
  19. my $file = shift;
  20. my $fh;
  21. if (UNIVERSAL::isa($file, 'GLOB')) {
  22.  $fh = $file;
  23. } else {
  24.  open($fh, '<', $file) || return undef;
  25. }
  26. binmode $fh;
  27. if (wantarray) {
  28.  <$fh>
  29. } else {
  30.  local $/;
  31.  <$fh>
  32. }
  33. }


 
si je puis me permettre, ton format de fichier n'est pas tres robuste. Que se passe t-il par exemple si l'utilisateur ecrit 'Opened By' dans le champ 'Problem Resolution'?

Reply

Marsh Posté le 25-01-2005 à 11:43:28   

Reply

Marsh Posté le 25-01-2005 à 12:01:21    

Merci vraiment beaucoup (ça se dit ça?)
Tu me sauve la vie là, sur 3 semaines que je rame dessus, toi en quelque minutes tu fais tout marcher.
Je suis vraiment pas fait pour le développement ^^;
 
En fait ce que je dois faire c'est réaliser un filtre sur un serveur de messagerie.
Des mails avec le texte que j'ai mis sont envoyer sur le serveur de messagerie. Le filtre reécupére les variables demander, en autre le numero, un description,... , met ça dans un autre fichier pour le reformuler apres, (voir les print).
 
Pour remaitre les variable dans un autre fichier, j'ai pensé a faire un fichier de référence, avec des nom de variable à remplacer par substitution en fait,
 
ex : Problem description:
desc1
 
je remplace desc1 par la chaine que j'ai extraite dans @description et j'enregistre le tout dans un autre fichier
donc en tout 3 fichiers, un avant, un de référence, et un apres.
 
Bon pour l'instant je suis rester sur ce model là mais si tu as d'autre conseil pour m'aider à améliorer le filtre je suis preneur.
 
Pas besoin de faire des testes sur les mot extrait vu que le fichier "avant" ne change jamais"

Reply

Marsh Posté le 25-01-2005 à 14:35:14    

ouai la subsitution dans un fichier de reference c'est pas mal, c'est un petit systeme de template en fait. rajoute un symbole autour, genre %desc1% pour etre certain qu'il n'y aura pas de conflict
 
tu slurp ton fichier de template, tu fait les subsitutions avec les bonnes valeurs, et tu le print dans un nouveau fichier.
 
par exemple:
 

Code :
  1. ...code precedent...
  2. my %replace = (
  3. call  => $call,
  4. description => $description,
  5. resolution => $resolution,
  6. id1  => $id1,
  7. id2  => $id2,
  8. );
  9. my $replace_regexp = join('|', keys %replace);
  10. $replace_regexp = qr/%($replace_regexp)%/;
  11. my $template = slurp("reference.txt" );
  12. $template =~ s/$replace_regexp/$replace{$1}/eg;
  13. print $template;


 
apres tu met tout ca proprement dans des subs (en gardant peut etre le contenu du template original dans une variable pour eviter de devoir recharger le fichier à chaque fois)

Reply

Marsh Posté le 25-01-2005 à 15:28:01    

<> c'est pas stdin, c'est l'entrée par défaut... Nuance ;) En particulier si un fichier est passé en paramêtre à Perl, alors <> lit ce fichier, pas stdin : perl -e '...' mon_fichier

Reply

Sujets relatifs:

Leave a Replay

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