hogehoge foobar Blog Style Beta

Web,Mac,Linux,JavaScript,Perl,PHP,RegExp,Git,Vim,Redmineなど技術的なことのメモや、ちょっと便利そうなものの紹介をしています。

PerlでCSVファイルやTSVファイルを列マージする

前回のエントリでは、csvファイルのある列を境にしてのファイル分割をしましたが、
今回は逆に2つに分かれているファイルを1つにマージする処理をPerlで書いてみました。
※ハッキリ言って、たいした内容じゃないです。

前回のエントリ:PerlでCSVファイルやTSVファイルを列で分割する

データサンプル

base.csv(元ファイル その1)
Key Deta2
1 A2
2 B2
3 C2
4 D2
5 E2
add.csv(元ファイル その2)
Key Deta1 Deta3
1 A1 A3
3 C1 C3
5 E1 E3

 ↓ マージ後 ↓

new.csv(マージされたファイル)
Key Deta1 Deta2 Deta3
1 A1 A2 A3
2 B2
3 C1 C2 C3
4 D2
5 E1 E2 E3

Perlで実装

今回もテキストファイルということでPerlで実装してみました。
処理の手順としては、

  1. 追加する側のファイル(行)を読み込み
  2. 読み込んだデータ(行)の1列目をキーとしてハッシュ配列を作成
  3. 追加される側のファイル(行)を読み込み
  4. 読み込んだデータ(行)の1列目をキーとして2.で作成したハッシュ配列からデータを取得
  5. マージ後の配列を作成しファイルに出力

といった感じになります。

ポイントとしては、ハッシュを使っているところくらいです。
今回の例の場合だと、base.csvに対してadd.csvの内容を追加する形になります。
base.csvとadd.csvに同じキーの行があれば、データが追加されますが、
add.csvにしかない行は出力(追加)されません。
base.csvにしか無い行は、そのまま(データ追加されずに)出力されます

以下がサンプルコードになります。
もう少しスマートな方法があるかもしれませんが、まずはこれでしばらく使ってみます。

サンプルソースコード(全部)
#!/usr/local/bin/perl
#
# merge_csv.pl
#
use strict;
use warnings;

my $delimiter = ',';
my %hash;

# FIle Open (add.csv)
open( IN, 'add.csv') or die $!;
while(<IN>){
    s/\r\n|\n|\r//g;
    my @row  = split/$delimiter/;
    
    # 1列目の項目をキーとしてハッシュに格納
    $hash{"$row[0]"} = \@row;
}
close(IN);

# FIle Open (base.csv & new.csv)
open( IN, 'base.csv') or die $!;
open( OUT, '> new.csv');
while(<IN>){
    s/\r\n|\n|\r//g;
    my @row_base = split/$delimiter/;
    
    # 1列目の項目をキーとしてハッシュからデータを取得
    my @row_add = $hash{"$row_base[0]"} ? @{$hash{"$row_base[0]"}} : ();
    my @row_new = ();

    # new.csv用に新しい配列にデータをセット
    $row_new[0] = $row_base[0];
    $row_new[1] = $row_add[1] ? $row_add[1] : '';
    $row_new[2] = $row_base[1];
    $row_new[3] = $row_add[2] ? $row_add[2] : '';

    print OUT join("$delimiter", @row_new) . "\n";
}
close(OUT);
close(IN);

今回参考にしたページ

SmartのWEB講座 > Perl講座 > ハッシュ
http://www.rfs.jp/sb/perl/02/05.html