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

  FORUM HardWare.fr
  Programmation
  Perl

  [PERL] regex !!!

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[PERL] regex !!!

n°2260065
web_olivie​r
R1 Powaaaaa
Posté le 10-06-2015 à 14:31:30  profilanswer
 

Bonjour,
 
Je m'arrache les cheveux avec mon faible niveau en perl et les regex ;)
 
Voila je lis un fichier qui contient par exemple les lignes suivante :
 
(salon on ou baie vitree on) et (cuisine on ou entree on)  
Salon on et (entree on ou cuisine on) et baie vitree on
((salon on ou entree on) et (baie vitree on et cuisine on)) ou chambre on
 
et je veux transformer ces lignes en :
 
(/salon on/ || /baie vitree on/) && (/cuisine on/ || /entree on/)
/salon on/ && (/entree on/ || /cuisine on/) && /baie vitree on/
((/salon on/ || /entree on/) && (/baie vitree on/ && /cuisine on/)) || /chambre on/
 
j'ai écris le code suivant en supposant que $cond contient les lignes du fichier, lues une par une dans une boucle.
 

Code :
  1. if ($cond=~/ ou /)
  2. {
  3. $cond=~s/ ou /\/ ou \//g;
  4. }
  5. if ($cond=~/\)\/ ou \/\(/)
  6. {
  7. $cond=~s/\)\/ ou \/\(/\) ou \(/g;
  8. }
  9. if ($cond=~/ et /)
  10. {
  11. $cond=~s/ et /\/ et \//g;
  12. }
  13. if ($cond=~/\)\/ et \/\(/)
  14. {
  15. $cond=~s/\)\/ et \/\(/\) et \(/g;
  16. }
  17. if ($cond=~/\)\/ et /)
  18. {
  19. $cond=~s/\)\/ et /\) et /g;
  20. }
  21. if ($cond=~/\/ et \/\(/)
  22. {
  23. $cond=~s/\/ et \/\(/\/ et \(/g;
  24. }
  25. $cond=~s/ et / && /g;
  26. $cond=~s/ ou / || /g;
  27. if ($cond =~ /\(/)
  28. {
  29. $cond=~s/\(/\(\//g;
  30. }
  31. if ($cond =~ /\(/)
  32. {
  33. $cond=~s/\)/\/\)/g;
  34. }
  35. if ($cond =~/^\w/)
  36. {
  37. $cond="/".$cond;
  38. }
  39. if ($cond =~ /\w$/)
  40. {
  41. $cond=$cond."/";
  42. }


 
Je n’excuse par avance pour ce code de débutant, mais c'est compliqué et ça ne marche pas !!!!
 
Quelqu'un peut m'aider et me montrer le chemin à suivre ?
 
Par avance merci.


Message édité par web_olivier le 10-06-2015 à 14:39:36
mood
Publicité
Posté le 10-06-2015 à 14:31:30  profilanswer
 

n°2260093
rat de com​bat
attention rongeur méchant!
Posté le 10-06-2015 à 17:45:18  profilanswer
 

Déjà une astuce pour améliorer nettement la lisibilité: On peut utiliser un autre séparateur que '/' pour les regex, p.ex. s!ceci!cela!. Du coup on peut mettre des '/' directement sans devoir écrire "\/".

 

C'est peut-être pas élégant mais plus court et ça fonctionne. Par contre faut faire la liste des mots une fois pour le premier regex.

 
Code :
  1. use strict;
  2. use warnings FATAL => 'all';
  3.  
  4. my $texte=<<ENDT;
  5. (salon on ou baie vitree on) et (cuisine on ou entree on)  
  6. Salon on et (entree on ou cuisine on) et baie vitree on
  7. ((salon on ou entree on) et (baie vitree on et cuisine on)) ou chambre on
  8. ENDT
  9.  
  10.  
  11. foreach my $cond (split(/\n/,$texte))
  12. {
  13.     $cond =~ s!((?:salon|baie vitree|cuisine|chambre|entree) on)!/$1/!g;
  14.     $cond =~ s! ou ! || !g;
  15.     $cond =~ s! et ! && !g;
  16.     print $cond,"\n";
  17. }
  18.  
  19.  
  20. __END__
  21. (/salon on/ || /baie vitree on/) && (/cuisine on/ || /entree on/)  
  22. Salon on && (/entree on/ || /cuisine on/) && /baie vitree on/
  23. ((/salon on/ || /entree on/) && (/baie vitree on/ && /cuisine on/)) || /chambre on/
 

Ca sent la domotique...

Message cité 1 fois
Message édité par rat de combat le 10-06-2015 à 17:45:38
n°2260095
rat de com​bat
attention rongeur méchant!
Posté le 10-06-2015 à 17:59:24  profilanswer
 

Sans devoir faire la liste des mots, hautement expérimental!! (autrement dit à tester intensivement avant utilisation ou faire valider par un pro)

 
Code :
  1. $cond =~ s!(^|\(|ou |et )([\w ]+?) on!$1/$2 on/!g;


(remplace le premier regex)


Message édité par rat de combat le 10-06-2015 à 18:00:57
n°2260105
gilou
Modérateur
Modzilla
Posté le 10-06-2015 à 20:37:11  profilanswer
 

La routine replace reçoit une ligne et renvoie la ligne modifiée

Code :
  1. my @data = ("(salon on ou baie vitree on) et (cuisine on ou entree on)  ",
  2.         "Salon on et (entree on ou cuisine on) et baie vitree on",
  3.         "((salon on ou entree on) et (baie vitree on et cuisine on)) ou chambre on " );
  4.  
  5. sub replace {
  6.  my $line = shift;
  7.  $line =~ s!^\s*!/!;
  8.  $line =~ s!\s*$!/!;
  9.  $line =~ s!(\(+)!$1/!g;
  10.  $line =~ s!(\)+)!/$1!g;
  11.  $line =~ s!\sou\s!/ || /!g;
  12.  $line =~ s!\set\s!/ && /!g;
  13.  $line =~ s!/\(!(!g;
  14.  $line =~ s!\)/!)!g;
  15.  return $line;
  16. }
  17.  
  18. my @replaced = map{replace($_)} @data;
  19. print join("\n", @replaced);


 
- D'abord je met des / en début et fin de ligne (si ils sont inutiles, ils seront effacés plus tard)
- Je remplace les (...( et )...) par (...(/ et /)...)
- Je remplace les ou et et par / || / et / && /
- Je vire les trucs qui devraient pas y être en remplaçant /( et )/ par ( et )
 
A+,


Message édité par gilou le 10-06-2015 à 22:21:48

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2260111
web_olivie​r
R1 Powaaaaa
Posté le 10-06-2015 à 22:19:24  profilanswer
 

Bonsoir,
 
Déjà merci à vous 2. :hello:  
 
Je regarde ça en détail et je vous tiens au courant.
Gilou merci pour les explications à venir :)

n°2260112
web_olivie​r
R1 Powaaaaa
Posté le 10-06-2015 à 22:40:48  profilanswer
 

Je viens de tester.
Gilou ça fonctionne parfaitement :love: :jap:  
Rat de combat, effectivement je triture ma domotique à la maison ;)  
Ta première solution fonctionne mais le script ne peut pas connaitre à l'avance le nom des capteurs. J'ai testé ta 2eme solution mais je me retrouve avec un / en trop au début et à la fin. Ceci dit chapeau quand même :jap:  
 
Un grand merci pour votre aide.

n°2260113
gilou
Modérateur
Modzilla
Posté le 10-06-2015 à 22:47:32  profilanswer
 

On peut optimiser un peu le sub (ou en tout cas en réduire la verbosité) ainsi:
 

Code :
  1. sub replace {
  2.  $_ = shift;
  3.  s!^\s*!/!;
  4.  s!\s*$!/!;
  5.  s!(\(+)!$1/!g;
  6.  s!(\)+)!/$1!g;
  7.  s!\sou\s!/ || /!g;
  8.  s!\set\s!/ && /!g;
  9.  s!/\(!(!g;
  10.  s!\)/!)!g;
  11.  return $_;
  12. }


 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2260114
gilou
Modérateur
Modzilla
Posté le 10-06-2015 à 23:02:50  profilanswer
 

Une petite note pour le rongeur guerrier:

rat de combat a écrit :

Déjà une astuce pour améliorer nettement la lisibilité: On peut utiliser un autre séparateur que '/' pour les regex, p.ex. s!ceci!cela!. Du coup on peut mettre des '/' directement sans devoir écrire "\/".
 
C'est peut-être pas élégant mais plus court et ça fonctionne. Par contre faut faire la liste des mots une fois pour le premier regex.
 

Code :
  1. use strict;
  2. use warnings FATAL => 'all';
  3.  
  4. my $texte=<<ENDT;
  5. (salon on ou baie vitree on) et (cuisine on ou entree on)  
  6. Salon on et (entree on ou cuisine on) et baie vitree on
  7. ((salon on ou entree on) et (baie vitree on et cuisine on)) ou chambre on
  8. ENDT
  9.  
  10.  
  11. foreach my $cond (split(/\n/,$texte))
  12. {
  13.     $cond =~ s!((?:salon|baie vitree|cuisine|chambre|entree) on)!/$1/!g;
  14.     $cond =~ s! ou ! || !g;
  15.     $cond =~ s! et ! && !g;
  16.     print $cond,"\n";
  17. }
  18.  
  19.  
  20. __END__
  21. (/salon on/ || /baie vitree on/) && (/cuisine on/ || /entree on/)  
  22. Salon on && (/entree on/ || /cuisine on/) && /baie vitree on/
  23. ((/salon on/ || /entree on/) && (/baie vitree on/ && /cuisine on/)) || /chambre on/


 
Ca sent la domotique...

Plutôt qu'un ENDT que tu lis de manière complexe, utiliser __DATA__ serait sans doute plus direct ici:
 

Code :
  1. use strict;
  2. use warnings FATAL => 'all';
  3.  
  4. while (<DATA> ) {
  5.  s!((?:salon|baie vitree|cuisine|chambre|entree) on)!/$1/!g;
  6.  s! ou ! || !g;
  7.  s! et ! && !g;
  8.  print;
  9. }
  10.  
  11. __DATA__
  12. (salon on ou baie vitree on) et (cuisine on ou entree on)  
  13. Salon on et (entree on ou cuisine on) et baie vitree on
  14. ((salon on ou entree on) et (baie vitree on et cuisine on)) ou chambre on


 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2260117
rat de com​bat
attention rongeur méchant!
Posté le 10-06-2015 à 23:31:59  profilanswer
 

Citation :

J'ai testé ta 2eme solution mais je me retrouve avec un / en trop au début et à la fin.


Je ne vois pas, où ça? Le résultat de mon script correspond à celui du script de gilou...?

 

Merci gilou pour le coup du __DATA__, je connaissais pas.

 
Citation :

rongeur guerrier


:D


Message édité par rat de combat le 10-06-2015 à 23:39:20
n°2260118
web_olivie​r
R1 Powaaaaa
Posté le 11-06-2015 à 00:25:01  profilanswer
 

Excuse rat de combat c'est moi qui faisais une erreur :(
Ta solution est donc encore plus "concentrée" :jap:
 
Merci à vous.

mood
Publicité
Posté le 11-06-2015 à 00:25:01  profilanswer
 

n°2260137
gilou
Modérateur
Modzilla
Posté le 11-06-2015 à 11:08:55  profilanswer
 

Euh, dans la solution de Rat de combat, il y a ce probleme: Salon n'est pas reconnu parce qu'il commence par une majuscule (début de la 2e ligne).
Il faut remplacer la ligne
s!((?:salon|baie vitree|cuisine|chambre|entree) on)!/$1/!g;
par
s!((?:salon|baie vitree|cuisine|chambre|entree) on)!/$1/!gi;
avec un i (case independent) pour régler le problème.
Et il vaut mieux mettre des \s+ dans ce genre d'expression:
s!((?:salon|baie\s+vitree|cuisine|chambre|entree)\s+on)!/$1/!gi;
A+,


Message édité par gilou le 11-06-2015 à 11:20:44

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2260175
web_olivie​r
R1 Powaaaaa
Posté le 11-06-2015 à 17:14:53  profilanswer
 

Merci Gilou, comme je ne connais pas le nom des capteurs il faut que j'utilise ta méthode ou la 2eme de rat de combat.
 
Je me permets de vous poser une autre question.
J'ai 2 tableaux, comment on peut les comparer ligne par ligne et trouver les lignes différentes (changement d'état).
 
Merci.

n°2260178
gilou
Modérateur
Modzilla
Posté le 11-06-2015 à 17:56:28  profilanswer
 

En utilisant le module Text::Diff, je pense.
 
A+,


---------------
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

  [PERL] regex !!!

 

Sujets relatifs
[Perl ] Comportement étrange avec DBICréer un exécutable à partir d'un script Perl
Problème RegEx et accenthelp programmation perl
[RESOLU][PERL] Extraire chaines multiples dans une fichierconfiguer perl sur wamp
Regex Longitudeperl + xml::treebuilder
perl + regex [resolu][PERL] Rechercher un / avec une regex
Plus de sujets relatifs à : [PERL] regex !!!


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