2017-09-20 2 views
0

J'ai un csv (séparé par,) avec multilines. Le csv a 4 colonnes, dont les 3 premières colonnes contiennent un texte multiligne tandis que le groupe arrive par la dernière colonne.Perl pour grouper des colonnes dans csv avec des multilignes

entrée teneur en csv: /tmp/test.tmp.csv

"Total Sections",ota,4!n,01 
"Input History",80,"HHMM28!c1!a[4!a] 
6X 
9X]",1 
"T (MR)",17t,(MTR),02 
"Input History",80,"HHMM28!c1!a[4!a] 
6X 
9X]",2 
Reference,:4!t/1c,:(Text1)/(Text2),30 
Reference,:4!t/1c,:(Text1)/(Text2),32 

dessus CSV est constitué de 6 disques, disques 2 et 4 sont avec multilignes.

Résultats attendus (groupe par espace séparé est):

"Total Sections",ota,4!n,01 
"Input History",80,"HHMM28!c1!a[4!a] 
6X 
9X]",1 2 
"T (MR)",17t,(MTR),02 
Reference,:4!t/1c,:(Text1)/(Text2),30 32 

Mon script perl (lire 3 premiers champs de hachage comme clé, le dernier champ de hachage en tant que valeur, impression au format CSV avec join):

#!/usr/bin/perl -w 

use strict; 
use warnings; 
use Text::CSV; 

my %hash; 
my @array; 
my $in_qfn = "/tmp/test.tmp.csv"; 
my $out_qfn = "/tmp/test.out.tmp.csv"; 

# Li: Parsing multilines in csv 
my $parser = Text::CSV->new({ 
    binary => 1, 
    auto_diag => 1, 
    sep_char => ',' 
}); 

# Li: output multilines to csv 
my $csvo = Text::CSV->new({ 
    binary => 1, 
    eol => "\r\n", 
    sep_char => ',' 
}); 

open(my $data, '<:encoding(utf8)', $in_qfn) or die "Could not open $in_qfn: $!\n"; 
open(my $sts, '>:encoding(utf8)', $out_qfn) or die "Could not write $out_qfn: $!\n"; 

while (my $fields = $parser -> getline($data)) { 
    my $fz = $fields->[0]; 
    my $fo = $fields->[1]; 
    my $ft = $fields->[2]; 
    my $fth = $fields->[3]; 
    my @flds = ($fz, $fo, $ft, $fth); 

    # Li: push the first 3 columns as key and the last column as value 
    push(@{$hash{@flds[0..2]} }, $flds[3]); 
} 

# Li: print to output csv without join yet 
for my $k (sort keys %hash) { 
    my @fldsAll = ($k, @{ $hash{$k}}); 
    print("###LI### 1: key: $k, value: @fldsAll\n"); 
    $csvo -> print($sts, \@fldsAll); 
} 

Cependant, le script ne fonctionne pas parfaitement, la clé de hachage est perdue en raison de la multiligne et peut-être des caractères spéciaux et sans guillemet partout.

Defected sortie:

(MTR),02 
4!n,01 
:(Text1)/(Text2),30,32 
"HHMM28!c1!a[4!a] 
6X 
9X]",1,2 

Toute idée sur la façon de résoudre ce problème? Ou une nouvelle solution perl est également appréciée.

+0

Vous attendez que la clé de hachage soit un tableau? Vous utilisez actuellement le dernier membre du tableau. –

+0

Oui, je m'attends à utiliser la tranche de tableau: @flds [0..2] comme clé de hachage. Est-ce que ce n'est pas correct? J'ai également essayé d'assigner @ fldsSlc = @ flds [0..2], et assignez le tableau @fldsSlc comme clé de hachage, même problème. – dellair

Répondre

1

Vous ne pouvez pas utiliser un tableau comme une clé de hachage comme vous l'avez fait car plutôt que d'utiliser toutes les valeurs, il utilise uniquement le dernier.

Et vous ne pouvez pas utiliser une référence au tableau car les clés ne sont pas liées aux valeurs du tableau. Prenez ce code exemple ...

for($i=0;$i<3;$i++) 
    { 
    my @a=(1,2,3); 
    $hash{\@a}=10; 
    } 

Parce que le champ d'@a est locale à la boucle, vous vous retrouvez avec 3 clés. Si vous mettez le my @a; en dehors de la boucle, vous vous retrouvez avec 1 clé. Vous pouvez changer le contenu du tableau et cela n'aurait aucun effet sur la clé. Au lieu de ce que vous aurez à faire est join le tableau en une seule chaîne.

push(@{$hash{join("\t",@flds[0..2])} }, $flds[3]); 

Je l'ai utilisé un onglet, mais une chaîne de caractères qui apparaîtront jamais dans l'une des 3 colonnes est ce que vous voulez, de sorte que si nécessaire, vous pouvez split ultérieurement pour obtenir les valeurs d'origine arrière.

+0

Cher @Chris Turner, cela a fonctionné. – dellair