csvファイルを読み込んでPerlのハッシュの配列に変換する
csv形式のファイルを読み込んで、ハッシュの配列に変換するサンプルです。
ハッシュスライスという機能を積極的に使っているので、可読性はちょっと低いです。Perlをしばらく使って慣れていないと暗号に見えるかもしれません。前回のサンプルとほぼ構造は同じなので、違う部分だけを解説します。
use strict;
use warnings;
# 引数の処理
my $file = shift;
unless ($file) {
die "Usage: $0 file"; # 引数がないときは、使用方法を示して終了。
}
# csvの各列に対応するキーを作成
my $headers = [ 'name', 'age', 'country' ];
# ファイルを解析してcsv形式のデータを配列の配列に変換。
# ヘッダのキーも引数として渡す。
my @recs = parse_file($file, $headers);
# 出力( ハッシュの配列なので、forでたどる )
for my $items ( @recs ){
# ハッシュスライスを利用して連結
print join(',', @{$items}{@$headers} ) . "\n";
}
# ファイル解析用の関数( 今回は単に書き戻すだけだけれど・・ )
sub parse_file {
my ($file, $headers) = @_;
open(my $fh, "<", $file)
or die "Cannot open $file for read: $!";
# 複数のレコードを格納する配列へのリファレンスを準備
my $recs = [];
while (my $line = <$fh>) {
# 改行を取り除く
chomp $line;
# データを格納するハッシュへのリファレンスを準備
# ハッシュスライスを利用してヘッダ
# に対応するキーに代入
my $items = {};
@{$items}{@$headers} = split(',', $line);
# push関数の第1引数は配列なので、@$recsとデリファレンス。
push @$recs, $items;
}
close $fh;
wantarray ? return @$recs : return $recs;
}
以下は、csvデータのサンプルです。csvファイルを作って、スクリプトの第1引数に与えて実行してください。
masao,10,Japan taro,20,USA rika,38,France
コード解説
(1)ハッシュのキーの配列の作成
my $headers = ['name', 'age', 'country'];
ハッシュのキーを使うことで、前回は単に配列であったものに意味をつけて挙げます。csvファイルの一項目目はnameに、2項目目はageに、3項目目はcountory に対応します。
(2)ファイルを読み込んで、csv形式のテキストをハッシュの配列に変換する
my @recs = parse_file($file, $headers);
parse_fileは、ファイルを読み込んで、csv形式のテキストをハッシュの配列に変換する自作の関数です。入力と出力のイメージは以下のようになります。
masao,10,Japan
taro,20,USA
rika,38,France
↓
@recs = (
{ name => 'masao', age => 10, country => 'Japan' },
{ name => 'taro', age => 20, country => 'USA' },
{ name => 'rika', age => 38, country => 'France' },
)
(3)ハッシュの配列を出力する
for my $items (@recs) {
print join(',', @{$items}{@$headers}) . "\n";
}
配列なので外側はforeachループになります。ハッシュへのリファレンスである$itemsをjoin関数でカンマで連結して出力します。
(3)-1 ハッシュスライスの解説
難解なハッシュスライス @{$items}{@$headers} を解説します。
まず $items はハッシュへのリファレンスで。
{ name => 'masao', age => 10, country => 'Japan' }
のようになっています。
デリファレンスするには普通 %$items としますが、ハッシュスライスを利用できるようにデリファレンスしたいので
@{$items}{ ハッシュのキーのリスト }
とします。
@{$items}{'name', 'age', 'country'}
と書くと
('masao', 10, 'Japan')
が取得できます。
また、$headers には、['name', 'age', 'country'] が代入されていますので、@$headers とデリファレンスすると('name', 'age', 'country') が取得できます。
@{$items}{@$headers}
という記述は、
@{$items}{'name', 'age', 'country'}
という記述と同じになり、
('masao', 10, 'Japan')
が取得できます。
join(',', @{$items}{@$headers})
として、カンマで結びつけて完成です。
(4)whileループでの処理
while文を使って、Perlのデータ構造を作成しています。
while (my $line = <$fh>) {
# 改行を取り除く
chomp $line;
# データを格納するハッシュへのリファレンスを準備
my $items = {};
# ハッシュスライスを利用してヘッダ
# に対応するキーに代入
@{$items}{@$headers} = split( ',', $line );
# push関数の第1引数は配列なので、@$recs
# とデリファレンス。
push @$recs, $items;
}
(4)-1 ハッシュへのリファレンスを用意
my $items = {}; # データを格納するハッシュへのリファレンスを準備
配列の中に持たせるハッシュへのリファレンスを準備します。
(4)-2 ハッシュスライスを左辺において対応するキーに代入
@{$items}{@$headers} = split(',', $line);
上記で解説したことと同じです。左辺をハッシュスライスにして、そこにsplit関数で分割したリストを代入します。
Perlゼミ

