2007年03月07日 01:00 [Edit]

勝手に添削 - PerlによるCSVファイルの高速集計 2

camel

前回に引き続き、今回も引き続きcodezineさんの添削。


添削後のコード

#!/usr/local/bin/perl
use strict;
use warnings;
use Text::CSV_XS;

my ($rfh, $wfh, %name_of, %addr_of);
my $tc = Text::CSV_XS->new({binary=>1}); # to handle non_ascii;

my $addr_file = shift or help();
my $q_file    = shift or help();
my $out_file  = shift;

open $rfh, "<", $addr_file or die "$addr_file:$!";
while(<$rfh>){
    next unless $tc->parse($_);
    my ($id, $name, $addr) = $tc->fields;
    $name_of{$id} = $name;
    $addr_of{$id} = $addr;
}
close $rfh;

if ($out_file){
    open $wfh, ">", $out_file or die "$out_file:$!";
}else{
    $wfh = \*STDOUT;
}

open $rfh, "<", $q_file or die "$q_file:$!";
while(<$rfh>){
    next unless $tc->parse($_);
    my ($id, @ans) = $tc->fields;
    my $name = $name_of{$id} || 'unknown';
    my $addr = $addr_of{$id} || 'unknown';
    $tc->combine($id, @ans[0..2],  $name, $addr);
    print $wfh $tc->string, "\n";
}

sub help{
    die "$0 address_file questionnaire_file [out_file]\n";
}

解説

CSVの処理はText::CSV_XSで

これは前回述べた通り。日本語が入っている場合でも{binary=>1}を指定すればOK。

Hash of Arraysより複数Hash

この例のアドレス帳のように、項目が少ない場合はHash of Arraysにアドレスをまとめていれるのではなく、項目ごとにHashを用意した方がよい。メモリー使用量も実はこちらの方が少ない。

なお、address.csvがもっと大きい場合は、一端DBMに変換してから処理すればよいだろう。

ファイル名は決め打ちしない

上記のようにやれば、コマンドラインから指定ができる上、ファイル名を変えてもスクリプトを書き換える必要がない。

openは3引数で

よほど古いperlを利用しているのであればとにかく、Perl 5.6以降であればなるべく"< $filename"ではなく"<", $filename とするよう心がける。セキュリティーの面を考えてもこちらの方がいい。

Dan the Perl Monger


この記事へのトラックバックURL

この記事へのトラックバック
以前に404 Blog Not Foundで「openは3引数で」というエントリを見たことがあって3引数を使うようにしていたんだけど、ログを吐くときに標準出力とファイル出力の出し分けをしようとしてどうやっていいのかわかんなかった。 どこで分岐させるのがいいの?openするの?どうす
[perl]3引数のopenで標準出力とファイル出力を出し分け【lesamoureusesの日記】at 2007年12月25日 19:53
この記事へのコメント
-よほど古いperlを利用しているのであればとにかく、
+よほど古いperlを利用しているのであればともかく、
Posted by X at 2007年03月07日 11:39