challenge RFC 4180対応版 CSVレコードの分解

ある関数(splitCSV)に渡された文字列を配列に分解して列ごとに表示してください。
渡される文字列は、CSVデータの1レコードが設定されているとします。

使用するデータはK3形式が元になっている仕様で
エクセルが出力しているような形式です。

書式には次のような特徴があります。
1. 各レコードは「改行」によって区切られている。
2. 各列は「,」によって区切られている。
3. 列のデータは「"」によって囲んでも良い。
4. 列に「,」「改行」「"」いずれかを含む場合「"」で
   囲わなければならない。
5. 列データに「"」を含める場合「""」とする。

本来、改行コードはCRLFですが今回は特に指定しません。

次の入力があった場合
"aaa","b
bb","ccc",zzz,"y""Y""y",xxx

出力は
1 => aaa
2 => b
bb
3 => ccc
4 => zzz
5 => y"Y"y
6 => xxx

となります。
このお題はraynstardさんの投稿によるものです。ご投稿ありがとうございます。助かります。

Posted feedbacks - Perl

Text::CSV_XSでさくっと.
1
perl -MText::CSV_XS -le '$csv = Text::CSV_XS->new({binary=>1}); $csv->parse("\"aaa\",\"b\nbb\",\"ccc\",zzz,\"y\"\"Y\"\"y\",xxx"); map { print ++$i, " => $_" } $csv->fields()'

昔書いたコードってホントよくわからないものですね(笑
サンプル出力するとうまく出るのでちゃんと機能しているはず^^;;

"aaa","b
bb","ccc","",zzz,"y""Y""y","xx,x",,,

1 => aaa
2 => b
bb
3 => ccc
4 =>
5 => zzz
6 => y"Y"y
7 => xx,x
8 =>
9 =>
10 =>
 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
40
41
sub splitCSV($@)
{
    my $work = shift || ''; # CSV形式の1レコードの文字列
    my $sepCHAR = shift || ',';     # 区切り文字 
    my $quoteCHAR = shift || '"';   # 引用符
    return 0 if( $work eq '' );

    $work .= $sepCHAR; # レコードの最後に , を追加
    # とりあえず列の取り出し;
    my @result = ($work =~ m/((?:$quoteCHAR$quoteCHAR|$quoteCHAR.*?[^$quoteCHAR]$quoteCHAR)[ \t]*|(?:.*?))$sepCHAR/sg);
    ######################
    # レコードのデータに
    # 引用符 が含まれていた場合
    # 引用符 を はずして 引用符二個で一つに変換する
    if( $work =~ m/$quoteCHAR/ ){
        my $count = 0;
        foreach $work ( @result ){
            #######################
            # 取り出した列の整形
            # ""のみはデータ無しで空白に置換
            $work = '' if( !defined($work) || $work eq "$quoteCHAR$quoteCHAR" );
            $work =~ s/$quoteCHAR(.+)$quoteCHAR/$1/s;       # " で囲まれていた場合 "を取り外す
            $work =~ s/$quoteCHAR$quoteCHAR/$quoteCHAR/g;   # "" は " に変換
            $result[ $count ++ ] = $work;                   # 変換後の結果で更新
        }
    }
    return @result;
}

my @field;
my $record = <<CSV;
"aaa","b
bb","ccc","",zzz,"y""Y""y","xx,x",,,
CSV

print "$record\n";
@field = &splitCSV($record);
for( my $n=0; $n<=$#field; $n ++)
{
	print "$n => $field[$n]\n";
}

Index

Feed

Other

Link

Pathtraq

loading...