Perlテックラボ

PerlでCSVを扱う - Text::CSV_XS

PerlでCSVを扱う場合、Text::CSV_XSモジュールが便利です。
インストールされていない場合、CPANを使ってインストールしましょう。

Text::CSV_XSのインストール
perl -MCPAN -e shell
install Text::CSV_XS

Text::CSV_XSを使ってCSVを読み込み、ファイルに出力する場合は以下の通りです。

#!/usr/bin/perl -w
use strict;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new ({ binary => 1 });
open my $fh, "<", "t.csv";
open my $fh_out, ">", "t.txt";
while (my $columns = $csv->getline ($fh)) {
print $fh_out map({ "[$_]\t" } @$columns), "\n";
}
$csv->eof;
close $fh_out;
close $fh;

データに日本語が含まれる場合は、new()の際に{binary=>1}オプションを設定します。

Text::CSV_XS->new({binary=>1});

ファイルをロックして書き込みたい場合は、Fcntlモジュールのflock()を使います。書き込みの前後ロックとロック解除のコードを追加するだけです。
ついでにIO::Fileを使って、ファイルの入出力もオブジェクト指向スタイルにしてみましょう。

#!/usr/bin/perl -w
use strict;
use Text::CSV_XS;
use IO::File;
use Fcntl qw(:flock);
# データに日本語が含まれる場合は{binary=>1}オプションを忘れずに
my $csv		= Text::CSV_XS->new({binary=>1});
my $io		= IO::File->new('./t.csv', "r");
my $io_out	= IO::File->new('./t.txt', "w");
flock($io_out, LOCK_EX);
while (not $io->eof and my $columns = $csv->getline($io)) {
$io_out->print(map({ "[$_]\t" } @$columns), "\n");
}
flock($io_out, LOCK_UN);
$io->close;
$io_out->close;

getline()はCSVから1カラムを読み出し、そのカラムをパースして配列リファレンスを返します。

$columns = $csv->getline($io)

getline()で取得した配列リファレンスの要素は下記のようにしてアクセスすることができますが、インデックスを指定する方法は可読性が悪いのが難です。

$columns = $csv->getline($io)
print $$columns[0];

下記のように、フィール名を用意しておいて、配列リファレンスの要素に対応させると、必要な要素に簡単にアクセスできるようになります。

# フィールド名の用意
my @f_name= qw/ id date category title text /;
while (not $io->eof and my $columns = $csv->getline($io)) {
my %field;
for ( my $i=0; $i<=$#f_name; $i++ ){
$field{$f_name[$i]}	= $$columns[$i];
}
# titleフィールドのみ出力
print $field{'title'},"\n";
}
参考

関連記事