2017-09-20 13 views
0

私は複数行でcsv(区切り)を持っています。 csvには4つの列があり、そのうちの最初の3列は複数行のテキストを含み、group byは最後の列で発生します。Perlがcsvの列を複数行でグループ化する

入力の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 

CSV上記は6、レコード、レコード2で構成され、図4は、マルチラインです。

の予想される出力(別によるグループがスペースです):

"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 

マイperlスクリプト(とcsvファイルに印刷、値としてハッシュでキーとしてハッシュの最初の3つのフィールド、最後のフィールドを読みます)参加:

#!/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); 
} 

しかし、スクリプトが完璧に動作しない、ハッシュキーが原因複数行、おそらく特殊文字にし、どこでも、二重引用符なしで失われてしまいました。

亡命出力

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

それを修正する方法上の任意のアイデア?または、まったく新しいPerlソリューションも高く評価されます。

+0

ハッシュキーが配列であると想定していますか?あなたは現在、配列の最後のメンバーを使っています。 –

+0

はいアレイのスライス:@flds [0..2]をハッシュキーとして使用します。それは間違っていますか?また、@ fldsSlc = @ flds [0..2]を割り当てようとし、配列@fldsSlcをハッシュキーとして同じ問題に割り当てようとしました。 – dellair

答えて

1

すべての値を使用するのではなく、最後の値のみを使用するため、配列をハッシュキーとして使用することはできません。

キーは配列の値に関連しないため、配列への参照は使用できません。 @aのスコープはループにローカルなので...

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

をこのコード例を取る、あなたは3つのキーで終わります。 my @a;をループの外側に置くと、1つのキーになります。配列の内容を変更することができ、キーには影響しません。

代わりにjoinを1つの文字列にする必要があります。

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

私はタブを使用しましたが、必要な場合は、元の値を取得するために、後でそれをsplitできるように、これまでに3列のいずれにも表示されません任意の文字列は、あなたが望むものですバック。

+0

親愛なる@Chris Turner、これはうまくいった。 – dellair

関連する問題