hogehoge foobar Blog Style Beta

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

PerlでCSVファイルやTSVファイルを列で分割する

csvファイルのある列を境にしてファイル分割が必要だったのでPerlで書いてみました。
今回やりたかった事としては、以下のhoge.csvからfoo.csvとbar.csvを生成するというものです。

データサンプル

hoge.csv(元ファイル)
NAME AGE ADDRESS MAIL TEL
Emacs 25 Tokyo emacs@example.com 03-XXXX-XXXX
Vi君 25 Sendai vi@example.com NULL
秀丸 20 Osaka hidemaru@example.com 06-XXXX-XXXX

 ↓ 分割後 ↓

foo.csv(分割されたファイル その1)
NAME AGE ADDRESS
Emacs 25 Tokyo
Vi君 25 Sendai
秀丸 20 Osaka
bar.csv(分割されたファイル その2)
MAIL TEL
emacs@example.com 03-XXXX-XXXX
vi@example.com NULL
hidemaru@example.com 06-XXXX-XXXX

Perlで実装

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

  1. ファイル(行)を読み込み
  2. 読み込んだデータ(行)をsplit(,)で配列に格納
  3. 配列の1〜3番目をjoin(,)して文字列として格納
  4. 配列の4〜5番目をjoin(,)して文字列として格納
  5. 格納した文字列をそれぞれのファイルに出力

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

ポイントとしては、添字の最大を表現する「$#row」。
例えば上記のhoge.csvだと、2行目のTELにNULLがセットされているのですが、
この状態で以下のようなコードで書くと警告が出てしまいました。(use warningsアリの場合)
指定した添字に対して配列の長さが足りないということで、警告が出てしまうようです。
なので、添字の最大については「$#row」のような形で動的に制御することで警告が出るのを防ぎました。

サンプルソースコード(ダメな例)
my $str_bar = join(',', @row[3..4]) . "\n";
サンプルソースコード(ダメな例)で発生する警告メッセージ(例)
Use of uninitialized value in join or string at split_csv.pl line 19, <IN_FILE> line 2.

上記の問題を解消した上で実装したコードが以下になります。
もう少しスマートな方法があるかもしれませんが、まずはこれでしばらく使ってみます。

・・・と思いましたが、下記のコードだと、

my $str_foo = join(',', @row[0..2]) . "\n";

で結局同じ問題が出てきてしまいますね。
うーん、あとで調べてみることにします。

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

# FIle Open
open( OUT_FOO, '> foo.csv') or die $!;
open( OUT_BAR, '> bar.csv') or die $!;
open( IN_FILE, 'hoge.csv') or die $!;

while(<IN_FILE>){
    s/\r\n|\n|\r//g;

    # 読み込んだ行をカンマ(,)で区切って配列(@row)へセット
    my @row  = split/,/;

    # $#row -> 添字の最大(4) 
    # ちなみに @row -> 要素数(5)
    my $str_foo = join(',', @row[0..2]) . "\n";  # データによっては警告が出ます。(Use of uninitialized value in join or string)
    my $str_bar = join(',', @row[3..$#row]) . "\n";

    # それぞれのファイルへ出力
    print OUT_FOO $str_foo;
    print OUT_BAR $str_bar;
}

# File Close
close(OUT_FOO);
close(OUT_BAR);
close(IN_FILE);

今回参考にしたページ

SmartのWEB講座 > Perl講座 > 配列
http://www.rfs.jp/sb/perl/02/04.html

uninitialized value
http://www.dab.hi-ho.ne.jp/sasa/biboroku/perl/uninitialized_value.html