Use FasterCSV or Ruby 1.9's CSV library

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック


を読んでいたら、標準CSV ライブラリの紹介が載っていた。知らなかったのだけれど、CSV ライブラリは1.9 系でFasterCSV に置き換えられたとのこと。
1.8 系以前のCSV ライブラリはそこまで使いやすいって感じじゃなかった。けれど、FasterCSV、1.9 系のCSV ライブラリを使うことで、CSV の操作をずっと簡単に行えることができるようになる!

CSV 形式のファイルを読み込む

例えば、ヘッダつきのCSV ファイルを読み込むなら、次のように書く必要があった。

require 'csv'

csv = CSV::Reader.parse(DATA)

header = nil

csv.inject([]) do |result, line|
  unless header
    header = line
  else
    result.push Hash[*header.zip(line).flatten]
  end

  result
end

__END__
id,name,age
1,kai,19
2,hong,20
3,bob,


これが、FasterCSV(または1.9 系のCSV) を使うと次のように書けるようになる。(DATA の内容は先のDATA の内容と同じ)

require 'rubygems'
require 'fastercsv'
require 'ruby-debug'

csv = FasterCSV.new(DATA, :headers => true, :header_converters => :symbol)
csv.first[:id]                                     # => "1"
csv.first[:age]                                    # => "20"


また、属性値を変換するConverter も指定することができる。ライブラリには日付と数値の属性値を変換するConverter が含まれていて、その他自分で作成したConverter も簡単に組み込める。
例えば、数値に変換できる値を変換するには、Converter として:integer を指定する。

csv = FasterCSV.new(DATA, :headers => true, :header_converters => :symbol, :converters => :integer)
csv.first[:id]                                     # => 1
csv.first[:age]                                    # => 20

CSV 形式のファイルを書き出す

書き出す場合も、以前のCSV ライブラリだと使いにくい部分があって、例えば以下のように使えるラッパーをつくってた。

User = Struct.new(:id, :name, :age)
elements = [
  User.new(1, 'kai', 19),
  User.new(2, 'hong', 20)
]

FileUtility.to_csv(elements, :header => %w[id name age]) do |e|
  [
    e.id,
    e.name,
    e.age
  ]
end

# => "id,name,age\n1,kai,19\2,hong,20\n"


この場合も、FasterCSV なら次のように書ける。

FasterCSV.generate(:headers => %w[id name age], :write_headers => true){|csv|
  elements.inject(csv){|c, e| 
    c << e
    c 
  }
}

# => "id,name,age\n1,kai,19\2,hong,20\n"


1.8 系のruby を使っているなら、fastercsv を使えばCSV 周りの処理はかなり楽になる丶(´▽`)ノ