gilou Modérateur Modzilla | Voila une version plus directe, au vu de tes données:
Code :
#!/usr/bin/perl use Modern::Perl; $_ = '2015/12/05 12:55:56.217 RmCmdSuccess,Cmd=CreateSession,RID=172.21.205.31,CmdTime=7ms,'; $_ .= 'SesId=0025643d7ecb/269123690,chan0=22,MPN=274,BW=2475007,GDA=0.0.0.0,UDP=56100,Tid=447885331'; my $result = '20151205125556|0025643d7ecb/269123690|2475007|0.0.0.0|LOG-01'; if (m|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+,Cmd=CreateSession,.+,SesId= ([^, ]+ ),.+,BW= ([^, ]+ ),GDA= ([^, ]+ ),| ) { print "$1$2$3$4$5$6|$7|$8|$9|LOG-01\n"; print "$result\n"; # pour comparer }
|
J'ai choisi |...| pour encadrer la regex plutôt que l'habituel /.../ parce qu'il y a des / dans la chaîne à parser (et que je suppose qu'il n'y aura pas de | dans cette chaîne).
si tu veux que ta regexp soit plus lisible, avec le modifier x, on peut la mettre sur plusieurs lignes:
Code :
if (m|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+, Cmd=CreateSession, .+, SesId=([^,]+), .+, BW=([^,]+), GDA=([^,]+),|x) { print "$1$2$3$4$5$6|$7|$8|$9|LOG-01\n"; print "$result\n"; # pour comparer }
|
Mais bon, une manière bien plus logique de procéder est la suivante:
Code :
#!/usr/bin/perl use Modern::Perl; $_ = '2015/12/05 12:55:56.217 RmCmdSuccess,Cmd=CreateSession,RID=172.21.205.31,CmdTime=7ms,'; $_ .= 'SesId=0025643d7ecb/269123690,chan0=22,MPN=274,BW=2475007,GDA=0.0.0.0,UDP=56100,Tid=447885331'; my $result = '20151205125556|0025643d7ecb/269123690|2475007|0.0.0.0|LOG-01'; if (/Cmd=CreateSession/) { my $time = shift @fields; $time =~ s|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+|$ 1$ 2$ 3$ 4$ 5$ 6|o; my %hash = map {if (/ (.+ )= (.+ )/ ) {($ 1, $ 2)}} @fields; print "$time|$hash{SesId}|$hash{BW}|$hash{GDA}|LOG-01\n"; }
|
Si on repère une ligne à traiter: if (/Cmd=CreateSession/)
On splitte les champs selon la virgule: my @fields = split /,/;
Ils sont tous de la forme XX=YYY sauf le premier.
On colle le premier champ dans une variable a part: my $time = shift @fields;
On colle les autres dans un hash, un champ de la forme XX=YYY fournissant un élment du hash de clé XX et de valeur YYY: my %hash = map {if (/(.+)=(.+)/) {($1, $2)}} @fields;
On extrait du premier champ de qui nous intéresse: $time =~ s|^(\d\d\d\d)/(\d\d)/(\d\d)\s(\d\d):(\d\d):(\d\d)\.\d+.+|$1$2$3$4$5$6|o;
qu'on envoie en sortie avec les valeurs du hash pour certaines clés: print "$time|$hash{SesId}|$hash{BW}|$hash{GDA}|LOG-01\n";
et c'est tout, zou!
Note:
J'ai écrit
my %hash = map {if (/(.+)=(.+)/) {($1, $2)}} @fields;
ça marche parce que je suis certain que tous les champs sont de la forme XX=YYY
Si je n'en suis pas sur, faire
my %hash;
map {if (/(.+)=(.+)/) {$hash{$1}=$2} @fields;
qui marche à tout les coups et ne tient compte que des champs de la bonne forme XX=YYY et saute ceux qui sont d'une autre forme.
En y repensant, un my %hash = grep /./, map {if (/(.+)=(.+)/) {($1, $2)}} @fields; fera la même chose (les champs d'une autre forme, qui renvoient undef avec map sont éliminés par le grep) et est un one liner.
Après, si on veut faire plus compact et moins lisible et maintenable, on peut toujours faire tout avec un hash unique:
Code :
if (/Cmd=CreateSession/) { my %hash = map {if (/ (.+ )= (.+ )/ ) {($ 1, $ 2)} elsif (m|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+| ) {('TimeStamp', "$1$2$3$4$5$6" )}} split /,/; print "$hash{TimeStamp}|$hash{SesId}|$hash{BW}|$hash{GDA}|LOG-01\n"; }
|
On peut rendre ça encore plus compact
Code :
#!/usr/bin/perl use Modern::Perl; $_ = '2015/12/05 12:55:56.217 RmCmdSuccess,Cmd=CreateSession,RID=172.21.205.31,CmdTime=7ms,'; $_ .= 'SesId=0025643d7ecb/269123690,chan0=22,MPN=274,BW=2475007,GDA=0.0.0.0,UDP=56100,Tid=447885331'; my $result = '20151205125556|0025643d7ecb/269123690|2475007|0.0.0.0|LOG-01'; my $date_regex = qr|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+|; if (/Cmd=CreateSession/) { elsif (m/ $date_regex/o ) {"$1$2$3$4$5$6"}} split(/,/, $_))), "|LOG-01\n"; }
|
Et si on veut, quitte a laisser tomber $result et a se placer dans le cadre de ton utilisation réelle (lecture en boucle ligne à ligne d'un log), on peut même aboutir à un one liner, guru-level illisible.
Code :
my $timestamp = qr|^ (\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+.+|; ... while (<$fh> ) { elsif (m/ $timestamp/o ) {"$1$2$3$4$5$6"}} split(/,/, $_))), "|LOG-01\n" if (/Cmd=CreateSession/ ); }
|
En ce qui me concerne, je ferais ceci:
Code :
my $date_regex = qr{(\d\d\d\d )/ (\d\d )/ (\d\d )\ s(\d\d ): (\d\d ): (\d\d )\.\d+ }; ... if (/Cmd=CreateSession/) { my ($timestamp, @fields) = split /,/; $timestamp =~ s/^ $date_regex .*/$ 1$ 2$ 3$ 4$ 5$ 6/o; my %hash = grep /./, map {if (/ (.+ )= (.+ )/ ) {($ 1, $ 2)}} @fields; print "$timestamp|$hash{SesId}|$hash{BW}|$hash{GDA}|LOG-01\n"; }
|
Parce que c'est lisible, compréhensible (pour qui pratique un peu Perl), et surtout, flexible et réutilisable: le jour ou tu veux imprimer une autre valeur de champ en sortie, par exemple celui associé à MPN, il te suffira de coller $hash{MPN} dans le print.
A+, Message édité par gilou le 06-12-2015 à 16:02:51 ---------------
There's more than what can be linked! -- Iyashikei Anime Forever! -- AngularJS c'est un framework d'engulé! --
|