たつをの ChangeLog : 2012-03-09

PerlによるCSVの読み込み方法。
既存のモジュール(Text::CSV等)を使わない場合について。

  • 今回の方法で想定するCSVフォーマット
    • 区切り文字はカンマ。
    • 各カラムはダブルクォートで囲み、内部のダブルクォートは二重にする。
    • カラム内にカンマ、ダブルクォート、改行コードがない場合はダブルクォートで囲まなくてもよい。
  • 注意
    • 警告なしに非対応フォーマットでも読み込んでしまう。「ダブルクォートの閉じ忘れ」など。
    • 「...,"",...」のように空要素をダブルクォートで囲んだ場合は「""」が出てきてしまう。

■コード(cvs.pl):
#!/usr/bin/env perl
use strict;
use warnings;

my $line = "";
while (<>) {
    $line .= $_;
    my @dqm = $line =~ /\"/g; # double quote を数える
    next if @dqm % 2; # 奇数なら次の行を末尾に足す
    chomp $line;
    { # 何かの処理
        print "\nINPUT: [$line]\n";
        my @c = split_csv($line);
        print "RESULT: ".join(", ", map {"($_)[$c[$_]]"} 0..$#c)."\n";
    }
    $line = "";
}

sub split_csv {
    my ($s) = @_;
    $s =~ s/""/\x07\x08/g;
    my @rv = ("$s," =~ /("[^"]+"|[^,]+|),/gs);
    return map {s/^"(.*)"$/$1/gs; s/\x07\x08/"/g; $_} @rv;
}

「\x07\x08」は一時退避用の適当な無意味文字列で、中身とマッチしなければOK。

■実行例:

テストファイル(csv-test.txt):
"ABC",DEF,"GHI,JKL"
"AB""C",,"D"",EF",","
this,foo
that,"foo+
bar",100
"4/
25","31/
365"
hoge,"hoge","hoge"
"hoge",hoge
"hoge","hoge/
hoge",hoge

実行結果:
% ./csv.pl csv-test.txt

INPUT: ["ABC",DEF,"GHI,JKL"]
RESULT: (0)[ABC], (1)[DEF], (2)[GHI,JKL]

INPUT: ["AB""C",,"D"",EF",","]
RESULT: (0)[AB"C], (1)[], (2)[D",EF], (3)[,]

INPUT: [this,foo]
RESULT: (0)[this], (1)[foo]

INPUT: [that,"foo+
bar",100]
RESULT: (0)[that], (1)[foo+
bar], (2)[100]

INPUT: ["4/
25","31/
365"]
RESULT: (0)[4/
25], (1)[31/
365]

INPUT: [hoge,"hoge","hoge"]
RESULT: (0)[hoge], (1)[hoge], (2)[hoge]

INPUT: ["hoge",hoge]
RESULT: (0)[hoge], (1)[hoge]

INPUT: ["hoge","hoge/
hoge",hoge]
RESULT: (0)[hoge], (1)[hoge/
hoge], (2)[hoge]

■ワンライナー:
応用として、CSVをTSVに変換するワンライナー。
CSVファイルの中にタブ文字がない前提。
あと改行入りカラムがない前提。
perl -nle '$,="\t";$_.=",";s/""/\t/g;print
map{s/^"(.*)"$/$1/g;s/\t/"/g;$_}/("[^"]+"|[^,]+|),/g;' csv-test.txt

参考


- CSVファイルフォーマットの解説:CodeZine
http://codezine.jp/article/detail/2364

- Common Format and MIME Type for Comma-Separated Values (CSV) Files
http://www.rfc-editor.org/rfc/rfc4180.txt
-- 今更だけどCSVのドキュメント[2005-12-06-2]

- perl - CSVはText::CSV(_XS)?で (404 Blog Not Found)
http://blog.livedoor.jp/dankogai/archives/50765677.html

追記


追記150128: 改行入りのカラムに対応しました。全面的に書き換えています。書き換え前のバージョンはウェブ魚拓で見てください。

今週の平日のランチの記録。

平日ランチ

■3/5(月) うどん

宮武讃岐製麺所[2010-02-02-5]でピリ辛豚味噌うどん。

■3/6(火) ラーメン

めんや 参◯伍[2010-03-26-2]で参◯伍郎らーめん。

■3/7(水) カレー

ゴーゴーカレーでカツカレー[2011-07-26-4]

■3/8(木) お弁当

社内売り弁当。和牛すき焼き。

■3/9(金) ハンバーガー

バーガーキングでワッパーJr.

たつをの ChangeLog
Powered by chalow