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

  FORUM HardWare.fr
  Programmation
  Perl

  Expression reguliere

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Expression reguliere

n°1127209
makko
Posté le 22-06-2005 à 11:34:21  profilanswer
 

bonjour,
 
Je realise une analyse d'une string de date, pour en retirer seulement certaines informations. Dans ce cadre, j'aurais aimer si il etait possible de faire en sorte que le quantifieur d'une expression (que je recupere dans la variable $2 predefini) recupere non pas la plus longue chaine par default, mais la premiere.
 
La string analysé sera soit de la forme :
  05-20-1934.18-30-55.1-255-4, soit:
  05-20-1934.18-30-55.153432.1-255-4
 
je n'ai besoin dans tous les cas que de 05-20-1934.18-30-55
 
Pour l'instant la solution fonctionne, mais est loin d'etre propre :
 

Code :
  1. my $date_test = '05-20-1934.18-30-55.1-255-4';
  2. my $date_temp;
  3. my $date_result;
  4. if ($date_test =~ /(.+)\.(.+)\..*/i){
  5.   $date_temp = "$1.$2";
  6.   if ($date_temp =~ /(.+)\.(.+)\..*/i){
  7.      $date_result = "$1.$2";
  8.   }
  9.   else
  10.   {
  11.   $date_result = $date_temp;
  12.   }
  13. }
  14. print "$date_result\n";


 
Existerait-il une solution plus simple ?
Merci
 
Makko

mood
Publicité
Posté le 22-06-2005 à 11:34:21  profilanswer
 

n°1127229
Elmoricq
Modérateur
Posté le 22-06-2005 à 11:45:22  profilanswer
 

Citation :

Existerait-il une solution plus simple ?


 
Oui, tu peux demander au moteur regexp d'être "moins gourmand" avec l'opérateur ?
 
Exemple :
 

Code :
  1. my $date_test = "05-20-1934.18-30-55.153432.1-255-4";
  2. (my $date_result = $date_test) =~ s/^(.*?)\.(.*?)\..*$/$1.$2/;
  3. print "$date_result\n";


 
 :)


Message édité par Elmoricq le 22-06-2005 à 11:45:40
n°1129615
makko
Posté le 24-06-2005 à 11:19:22  profilanswer
 

C'est ce que je cherchais !
Merci bien !! (et en plus, quel rapidité sur la reponse :) )

n°1129621
denzz
huhuuuuu ! (désolé )
Posté le 24-06-2005 à 11:22:56  profilanswer
 

elmoricq est le sauveur de tous les codeurs perl de france, en tout cas de hfr, et il s'acquitte très bien de sa tache effectivement :)

n°1192059
ypnoize
Posté le 05-09-2005 à 10:40:20  profilanswer
 

denzz a écrit :

elmoricq est le sauveur de tous les codeurs perl de france, en tout cas de hfr, et il s'acquitte très bien de sa tache effectivement :)


 
Salut tout le monde, moi aussi g un pb de regexp.Je fais appel aux experts.  
Il faut considérer la chaine si dessous les différents champs sont séparés par une virgule:
UPDATE,"a",3,"b,c"d"e",h,g,1389,"i","j","k","l","m","n","o",p,"q","r",0,"s","t"
 
Voila les champs de la chaine qu'il faudrait que je récupère.  
 
champs numérotés a récuperer:
1: UPDATE  
2: "a"  
3: 3  
4: "b,c"d"e" (guillemets à l'inrérieur de guillemets)
5: h  
6: g  
7: 1389
8: "i"  
9: "j"  
10: "k"  
11: "l"
12: "m"  
13: "n"  
14: "o"  
15: p  
16: "q"  
17: "r"
18: 0  
19: "s"  
20: "t"  
 
je te donne aussi la regexp  mais le problème c qu'il y a des guillemets dans les guillemets:  
 
(...)  
my @b =  grep { !/^$/ } split(/("[^"]+" )?,/,$file[$i]);  
(...)  
 
n'en tiens pas compte elle ne marche que dans le cas ou il n'y a pas de guillemets dans les guillemets.
 
voila merci d'avance


Message édité par ypnoize le 05-09-2005 à 11:44:16
n°1192163
Elmoricq
Modérateur
Posté le 05-09-2005 à 12:22:51  profilanswer
 

denzz a écrit :

elmoricq est le sauveur de tous les codeurs perl de france, en tout cas de hfr, et il s'acquitte très bien de sa tache effectivement :)


 
http://pix.nofrag.com/8c/2a/9c119f6e4746b8d63ba83562ffb7.jpg
 

ypnoize a écrit :

Salut tout le monde, moi aussi g un pb de regexp.Je fais appel aux experts.  
Il faut considérer la chaine si dessous les différents champs sont séparés par une virgule:
UPDATE,"a",3,"b,c"d"e",h,g,1389,"i","j","k","l","m","n","o",p,"q","r",0,"s","t"


 
Euh, c'est franchement tordu ton truc, là.
Je vais te dire : je ne vois aucune solution qui soit totalement exempte de bugs. Le format est inconsistant, il y a forcément des cas qui seront indétectables.
 
Que faire par exemple si on a : UPDATE,"a",3,"b,c"d,e,f"e",h,g,... ?
 
Si encore au lieu de guillemets on avait des parenthèses fermantes et ouvrantes, ce serait facile, mais là impossible de savoir si un guillemet en referme un autre ou au contraire marque le début d'une sous-chaîne. A la limite on pourrait le déduire si on n'avait pas de virgule à l'intérieur de ces chaînes, mais non, il peut y avoir des virgules aussi.
Bon courage :sweat:
 
Je peux te proposer cette solution, qui fonctionne avec l'exemple que tu donnes, mais qui est loin d'être 1. élégante et 2. 100% fiable.
Encore une fois, je ne vois aucune solution pour découper ta chaîne qui fonctionne à tout coup. C'est impossible. Change de format.
 
"Solution" que je te propose, donc :
 

#!/usr/bin/perl
 
use strict;
 
my $separateur = ';'; # par exemple...
my $chaine = 'UPDATE,"a",3,"b,c"d"e",h,g,1389,"i","j","k","l","m","n","o",p,"q","r",0,"s","t"';
 
my ($flag, @lettres) = (0,);
foreach my $lettre ( split //, $chaine )
{
    ($flag = 1 - $flag) if ( $lettre eq '"' );
    ($lettre = $separateur ) if ( $lettre eq ',' and not $flag);
     
    push @lettres, $lettre;    
}
 
my @champs = split $separateur, join('', @lettres);
foreach my $i ( 0..$#champs )
{
    printf("Numéro : %s, champ : %s\n", $i + 1, $champs[$i]);
}


 
Mais je n'en suis pas fier, je trouve ça laid et cet exemple rate la détection si une virgule se trouve présente dans une sous-chaîne. Entre autres.


Message édité par Elmoricq le 05-09-2005 à 12:28:46
n°1192213
ypnoize
Posté le 05-09-2005 à 13:23:25  profilanswer
 

Elmoricq a écrit :

http://pix.nofrag.com/8c/2a/9c119f [...] 62ffb7.jpg
 
 
 
Euh, c'est franchement tordu ton truc, là.
Je vais te dire : je ne vois aucune solution qui soit totalement exempte de bugs. Le format est inconsistant, il y a forcément des cas qui seront indétectables.
 
Que faire par exemple si on a : UPDATE,"a",3,"b,c"d,e,f"e",h,g,... ?
 
Si encore au lieu de guillemets on avait des parenthèses fermantes et ouvrantes, ce serait facile, mais là impossible de savoir si un guillemet en referme un autre ou au contraire marque le début d'une sous-chaîne. A la limite on pourrait le déduire si on n'avait pas de virgule à l'intérieur de ces chaînes, mais non, il peut y avoir des virgules aussi.
Bon courage :sweat:
 
Je peux te proposer cette solution, qui fonctionne avec l'exemple que tu donnes, mais qui est loin d'être 1. élégante et 2. 100% fiable.
Encore une fois, je ne vois aucune solution pour découper ta chaîne qui fonctionne à tout coup. C'est impossible. Change de format.
 
"Solution" que je te propose, donc :
 
 
Mais je n'en suis pas fier, je trouve ça laid et cet exemple rate la détection si une virgule se trouve présente dans une sous-chaîne. Entre autres.


 
 
Bon je vais essayer de te remonter le moral.  
je te montre ce que j'ai à parsé, les guillemets ne changent jamais de place et les champs ont été fixés à l'avance sauf que dans le cas de la description de l'alarme ou des guillemets peuvent apparaitre au sein mêm de ce champs:
 
UPDATE: 38814130,
"xxx-xxx-sup-05",
3,
"Data Warehouse Maintenance Program Error, Return Code: 2, Error: Lock of "/var/opt/OV/share/databases/xxxxxx" failed..    Another instance of xxx, xxx or xxx may be running..    If this is not the case, remove /var"(champs description),
08/02/05 12:03:00,
09/01/05 14:29:00,
1389,
"xxx-xxx-xxx-05",
"",
"",
"",
"Client xxx",
"","xxx-xxx-xxx-05",
09/01/05 14:29:00,
"",
"",
0,
"",
""
 
le délimiteur "," ne peut pas etre modifier logiciel propriètaire et je n'ai pas la main sur la description des alarmes.
 
j'ai commencé à essayer de reconnaitre les différents champs en structurant ma reg exp mais la je ne vois pas comment récuperer le champs description correctement, on peut etre jouer sur le ," au debut de la description et le ", à la fin?  
 
voila ce que ca donne:
 
#! /usr/bin/perl
if ( $string =~ m/(\w\w\w\w\w\w): (\d*),"(\w*\W*\w*\W*\w*\W*\d*)",(\d)/)
{
        print "1:$1\n";
        print "2:$2\n";
        print "3:$3\n";
        print "4:$4\n";
        print "5:$5\n";
}
 
en esperant pas t'assomer :pt1cable: !

n°1192237
Elmoricq
Modérateur
Posté le 05-09-2005 à 13:47:00  profilanswer
 

Ah, mais ce n'est plus du tout pareil, là. C'est beaucoup plus simple.
 
Parce qu'à une exception près, chaque champ se termine par un saut de ligne (caractère \n). Et que l'emplacement de ces champs est fixe.
 
L'exception est un champ de description, qui se termine par ",\n ;)
 
Il te suffit donc de lire ton fichier ligne à ligne, et pour ce champ description, de lire toutes les lignes jusqu'à celle qui se termine par ",\n (regexp : m/\",\n$/ ).
 
EDIT : Je te suggère de passer par une table de hâchage pour stocker tes champs, comme ça tu pourras y accéder très facilement.


Message édité par Elmoricq le 05-09-2005 à 13:48:32
n°1192362
ypnoize
Posté le 05-09-2005 à 15:45:30  profilanswer
 

Elmoricq a écrit :

Ah, mais ce n'est plus du tout pareil, là. C'est beaucoup plus simple.
 
Parce qu'à une exception près, chaque champ se termine par un saut de ligne (caractère \n). Et que l'emplacement de ces champs est fixe.
 
L'exception est un champ de description, qui se termine par ",\n ;)
 
Il te suffit donc de lire ton fichier ligne à ligne, et pour ce champ description, de lire toutes les lignes jusqu'à celle qui se termine par ",\n (regexp : m/\",\n$/ ).
 
EDIT : Je te suggère de passer par une table de hâchage pour stocker tes champs, comme ça tu pourras y accéder très facilement.


 
 
Ha excuse moi ct par souci de clarté que g séparé les champs d'un \n  :sweat: mais mon alarme n'est que sur une seule ligne, je dois traiter un fichier ou chaque alarmes tient sur une ligne  encore Sorry  
allez on se reprend la tete  :??:  

n°1192367
Elmoricq
Modérateur
Posté le 05-09-2005 à 15:51:49  profilanswer
 

Comme je te l'ai dit, sur une seule ligne il n'y a pas de solution universelle. Celle que je t'ai donné devrait fonctionner correctement, sauf pour le champ "","xxx-xxx-xxx-05",.
 
Ou alors tu fais du positionnel, en traitant chaque champ potentiel en fonction de ce qu'il devrait contenir. C'est lourd et galère, mais c'est sans doute la seule solution.
 
Et je sais pas qui est le fournisseur de ces données, mais faudra lui dire que c'est bien nul ce bazar.

mood
Publicité
Posté le 05-09-2005 à 15:51:49  profilanswer
 

n°1193236
ypnoize
Posté le 06-09-2005 à 14:59:42  profilanswer
 

Elmoricq a écrit :

Comme je te l'ai dit, sur une seule ligne il n'y a pas de solution universelle. Celle que je t'ai donné devrait fonctionner correctement, sauf pour le champ "","xxx-xxx-xxx-05",.
 
Ou alors tu fais du positionnel, en traitant chaque champ potentiel en fonction de ce qu'il devrait contenir. C'est lourd et galère, mais c'est sans doute la seule solution.
 
Et je sais pas qui est le fournisseur de ces données, mais faudra lui dire que c'est bien nul ce bazar.


 
Je sais... Mais bon fau faire avec et avancer. Alors j'ai résolu mon problème grace à des substitutions comme ci dessous:
 
$file[$i] =~ s/",/|/g;
$file[$i] =~ s/,"/|/g;
$file[$i] =~ s/\|"/|/g;
 
et ensuite g splité les autres champs comme les dates en fonction de la virgule, c sale mais ca marche dans tous les cas.
 
Merci beaucoup pour ton aide  Elmoricq

n°1193756
pospos
Posté le 07-09-2005 à 03:50:39  profilanswer
 

ca devrait marcher:

Code :
  1. my @liste = $str =~ /(?:(?<=,)|^)(".*?"|[^,]*)(?:(?=,)|$)/g;

n°1193940
ypnoize
Posté le 07-09-2005 à 11:55:43  profilanswer
 

pospos a écrit :

ca devrait marcher:

Code :
  1. my @liste = $str =~ /(?:(?<=,)|^)(".*?"|[^,]*)(?:(?=,)|$)/g;



On voit que la nuit porte ses conseils, ta regexp marche. Merci à tous de votre aide.
PS: pospos tu règles mon pb en 1 ligne je le règle en 10 bien joué! :) mais je comprend pas tout, voila mon mail peux tu me l'expliquer pas à pas si tu as le temps. msn:un_truc_a_gerber@hotmail.com  


Message édité par ypnoize le 07-09-2005 à 12:09:31
n°1193949
Elmoricq
Modérateur
Posté le 07-09-2005 à 12:05:32  profilanswer
 

pospos a écrit :

ca devrait marcher:

Code :
  1. my @liste = $str =~ /(?:(?<=,)|^)(".*?"|[^,]*)(?:(?=,)|$)/g;



 [:banditsuzukixp]  
 
Woah, j'ai dû sortir mon bouquin pour comprendre la signification de ?<= et ?=, je ne savais pas que ça existait un truc pareil. Drôlement chouette, j'ai l'air tout con avec ma boucle maintenant.
 
Belle regexp.  [:stukka]

n°1194150
pospos
Posté le 07-09-2005 à 14:49:57  profilanswer
 

merci Elmoricq
 
en fait le premier look behind est inutile:

Code :
  1. my @liste = $str =~ /(?:,|^)(".*?"|[^,]*)(?:(?=,)|$)/g;


Message édité par pospos le 07-09-2005 à 14:50:18

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

  Expression reguliere

 

Sujets relatifs
Expression reguliereexpression reguliere
problème expression regulière[PHP] Expression régulière
expression reguliere replaceAll()Expression régulière
[javascript] pb expression régulièrePtit prob d'expression régulière
[Javascript] + Expression Reguliereexpression reguliere avec code source
Plus de sujets relatifs à : Expression reguliere


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