Multiple captures par regexp ?
Bonjour à tous,
voilà mon petit souci. J'ai un fichier comportant sur chaque ligne un certain nombre de champs se suivant séparés par un espace et définis ainsi :
<NOM_CHAMP>:<VALEUR>
Je ne connais pas à l'avance les noms des champs, ni leur nombre. Les valeurs peuvent prendre à peu près n'importe quelle forme (alphanumérique, quelques symboles y compris espace et deux-points...).
Mon but est, vous l'aurez compris, de recréer un tableau plus classique à partir de ce fichier (au format type csv par exemple).
On peut prendre les règles suivantes quand même (pour simplifier un peu - voir script) :
1. pas de point-virgule ou de guillemets ou de caractères trop "chiants" =)
2. un nom de champ commence par une lettre et ne contient que des caractères alphanumériques ou underscore
3. conclusion de 1 & 2 : je repère chaque champ en trouvant un espace suivi d'une lettre éventuellement plusieurs caractères alphanumériques ou underscore et deux-points
J'ai réussi à faire un script qui fonctionne plutôt bien MAIS qui me pose problème au traitement du dernier champ de la ligne ^^ :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #!/usr/bin/perl
use strict;
open (FIC_E, "dsv.txt") or die ("dsv.txt : $!");
open (FIC_S, ">dsv.csv") or die ("dsv.csv : $!");
my $result;
my @keys;
my $nbrow=0;
while (<FIC_E>) {
my @matches = m/(?:([a-zA-Z]\w+)\:(?:(.*?)\s?)(?=[a-zA-Z]\w+\:))/g;
next if ($#matches <= 0);
for (my $i=0; $i <= $#matches+1; $i+=2) {
push (@{$result->{$matches[$i]}}, $matches[$i+1]);
push (@keys,$matches[$i]) if ($nbrow == 0);
}
if (/([a-zA-Z]\w+)\:$/) {
push (@{$result->{$1}}, "");
push (@keys,$1) if ($nbrow == 0);
}
$nbrow++;
}
foreach my $key (@keys) {
print FIC_S $key,";";
}
print FIC_S "\n";
for (my $i=0; $i < $nbrow; $i++) {
foreach my $key (@keys) {
print FIC_S '"',$result->{$key}->[$i],'";';
}
print FIC_S "\n";
}
close FIC_E;
close FIC_S; |
La partie intéressante ici est bien entendu ma regexp :
Code:
1 2 3 4 5
| #m/(?:
# ([a-zA-Z]\w+)\: ==> définition d'un nom de champ : une lettre + alphanum ou underscore...
# (?:(.*?)\s?) ==> capture des valeurs correspondantes : le \s? est là pour virer le dernier espace (oui, un champs peut n'être composé que d'espaces)
# (?=[a-zA-Z]\w+\:) ==> je m'arrête quand je détecte un nouveau nom de champ
#)/g |
Il y a peut-être (sûrement) mieux ? Quoiqu'il en soit, ça marche bien comme je l'ai dit, sauf pour le dernier champ puisqu'il ne trouve pas de nouveau nom de champ à la suite :(
Exemple
mon entrée:
Code:
1 2 3
| VAR:10 ID:0000000001 DATE: 2008-04-19 14:12:55
VAR: 1 ID: DATE: 2008-04-19 14:13:15
VAR:10 ID:0000000009 DATE: 2008-04-19 14:14:32 |
ma sortie:
Code:
1 2 3 4
| VAR;ID;
"10";"0000000001";
" 1";" ";
"10";"0000000009"; |
ce que je voudrais:
Code:
1 2 3 4
| VAR;ID;DATE;
"10";"0000000001";" 2008-04-19 14:12:55";
" 1";" ";" 2008-04-19 14:13:15";
"10";"0000000009";" 2008-04-19 14:14:32"; |
merci =)