2013年2月26日火曜日

Ruby 手抜きレシピ: CSV ファイルの結合

先日 Ruby 2.0 がリリース されましたね。しばらく Ruby はレガシーな使い方しかしてないものの、キーワード引数やデフォルトUTF-8エンコーディングなど便利そうな機能も多く楽しみです。

さて、今回は 2 つの CSV ファイルを結合する手抜きのサンプルスクリプトのご紹介。ある日友人から

  • Windows 環境で
  • 2つの CSV ファイルを横に連結したく
  • たまたまその環境で動くのが Ruby だったので Ruby で処理できるといいな (その友人は数値処理系のプログラムはガシガシ書けるけど Ruby はあまり触ったことない)

という相談を受け、ちょろっと書いてみたスクリプトが以下になります (ダウンロード)。

#!/usr/bin/ruby
########################################
#### Settings
DELIM=","

########################################
#### Main Program

if ARGV.size < 3
  print <<-"EOH"

    USAGE: ruby #{$0} <IN-FILE1> <IN-FILE2> <OUT-FILE>

EOH
  exit 1
end

in1, in2, out = ARGV[0..2]

in1lines = File.open(in1).read.split("\n")
in2lines = File.open(in2).read.split("\n")
out_io   = File.open(out, "w")

in1size = in1lines.size
in2size = in2lines.size

line_num = in1size > in2size ? in1size : in2size

for n in 1..line_num
  in1dat = in1lines[n-1] ||= ""
  in2dat = in2lines[n-1] ||= ""
  out_io.puts in1dat + DELIM + in2dat
end

out_io.close

何をするかというと、以下のような 2 つの CSV ファイルがある時に、

$ cat file1.csv
1,2,3
4,5,6
7,8,9

$ cat file2.csv
A,B,C
D,E,F
G,H,I

こんなふうに連結しますよというもの。

$ ruby join_csv.rb file1.csv file2.csv out.csv
$ cat out.csv

1,2,3,A,B,C
4,5,6,D,E,F
7,8,9,G,H,I

お気づきの方はお気づきの通り 「それ paste(1) コマンドでできますやん」ということで全くその通りですw。paste コマンドだと以下の使い方で OK ですね。

$ paste -d, file1.csv file2.csv > out.csv

まあ、今回はたまたま Windows 上でやりたかったということで無意味ではなかったのかなと… (汗)

上記スクリプトは行数を圧縮したくて Ruby 特有の記法で書いてる部分もありますので、もうちょっと平易に書いたものも載せておきます。(ダウンロード

#!/usr/bin/ruby
########################################
#### Settings
DELIM=","

########################################
#### Main Program

if ARGV.size < 3
  print <<-"EOH"

    USAGE: ruby #{$0} <IN-FILE1> <IN-FILE2> <OUT-FILE>

EOH
  exit 1
end

in1 = ARGV[0]
in2 = ARGV[1]
out = ARGV[2]

in1lines = File.open(in1).read.split("\n")
in2lines = File.open(in2).read.split("\n")
out_io   = File.open(out, "w")

in1size = in1lines.size
in2size = in2lines.size

if in1size > in2size
  line_num = in1size
else
  line_num = in2size
end

for n in 1..line_num
  in1dat = in1lines[n-1]
  unless in1dat 
    in1dat = ""
  end

  in2dat = in2lines[n-1]
  unless in2dat 
    in2dat = ""
  end

  out_io.puts in1dat + DELIM + in2dat
end

out_io.close

"Ruby CSV 結合" でググると CSV クラス の話などは出てくるのですが、意外に今回のような要望にヒットする記事がないもんだなぁと思い、枯れ木も山のなんとやらで書いてみました。

このレベルのスクリプトはちょこちょこ書いてるものの、プログラミングに関する知識やコーディングの考え方など、ニュース追っててもピンと来ないものも多く、まだまだ時代に追いつけてないなぁと実感します。そっち方面ももっと勉強しないといけませんが、まあそのうち…。

0 件のコメント:

コメントを投稿