Expression reguliere

Expression reguliere - Perl - Programmation

Marsh Posté le 22-06-2005 à 11:34:21    

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

Reply

Marsh Posté le 22-06-2005 à 11:34:21   

Reply

Marsh Posté le 22-06-2005 à 11:45:22    

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
Reply

Marsh Posté le 24-06-2005 à 11:19:22    

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

Reply

Marsh Posté le 24-06-2005 à 11:22:56    

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

Reply

Marsh Posté le 05-09-2005 à 10:40:20    

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
Reply

Marsh Posté le 05-09-2005 à 12:22:51    

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
Reply

Marsh Posté le 05-09-2005 à 13:23:25    

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

Reply

Marsh Posté le 05-09-2005 à 13:47:00    

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
Reply

Marsh Posté le 05-09-2005 à 15:45:30    

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

Reply

Marsh Posté le 05-09-2005 à 15:51:49    

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.

Reply

Marsh Posté le 05-09-2005 à 15:51:49   

Reply

Marsh Posté le 06-09-2005 à 14:59:42    

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

Reply

Marsh Posté le 07-09-2005 à 03:50:39    

ca devrait marcher:

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

Reply

Marsh Posté le 07-09-2005 à 11:55:43    

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
Reply

Marsh Posté le 07-09-2005 à 12:05:32    

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]

Reply

Marsh Posté le 07-09-2005 à 14:49:57    

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
Reply

Sujets relatifs:

Leave a Replay

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