RubyでCSVファイルの読み込みを行う

Pocket

blog_5575021761_26b97bc9be_b

RubyでCSVファイルを処理するコードを書くときに、どのライブラリーを使えばいいのかいつも戸惑う。

今回も仕事でCSVファイルからデータを読み込んで、HTMLに出力するというちょっとしたスクリプトを書く必要があったのだが、またもや戸惑ってしまった。

これを機にどのような方法があるのか整理してみた。

CSVの取り扱いには、下記の3つの方法があるようだ。

  1. 通常のファイルとしてCSVを扱う
  2. Rubyに組み込まれているCSVライブラリーを利用する
  3. FasterCSVライブラリーを利用する

以下それぞれ詳しく説明していく。

1. 通常のファイルとしてCSVを取り扱う方法

ファイル入出力の関数を利用して、普通の方法でファイルを開き、一行ずつデータを読み込む方法である。

下記のサンプルはopenメソッドでファイルを開いた後、getsメソッドで一行ずつ読み取り、配列に格納している。なおgetsメソッドで得られる文字列は末尾に改行も含まれるので、chompメソッドで末尾の改行を削除し、splitメソッドで配列化している。

open("list.csv") do |file|
    while l = file.gets
        array = l.chomp.split(",")
        p array
    end
end

ちなみにTAB区切りのCSVファイルであれば、splitを下記のように変更すればOK。

open("list.csv") do |file|
    while l = file.gets
        array = l.chomp.split("\t")
        p array
    end
end

データの内容がシンプルであったり、フォーマットが約束されている場合は、通常のファイルを扱う方法でCSVファイルを処理すれば十分だと思う。

ただこの方法だと下記のようにデータの中にCSVのセパレーターであるカンマ(,)が含まれているとうまく処理できないはず。したがって、そのあたりも考慮にいれてまじめに実装する場合は、もっと手の込んだことをしなければならない。

list.csv

num,name
1,taro
2,"yamada,hanako"

あまり細かいことを考えずに、CSVデータの処理を真面目に実装したい場合は、後述のCSVライブラリーを利用する方法がよさそうだ。

2. Ruby標準のCSVライブラリーを利用する方法

CSVのライブラリーを利用する方法は下記の通り。セパレータのデフォルトはコンマ(,)。

require 'csv'
CSV.foreach("list.csv") do |row|
    p row
end

foreachメソッドでオプションを追加すると、文字コード、セパレーター、囲み文字等の指定もできる。 ただし、このオプションが使えるのはRuby1.9以降だけのようだ。

require 'csv'
CSV.foreach("list_tab.csv", { :encoding => "UTF-8", :col_sep => "\t", :quote_char => '"' }) do |row|
    p row
end

CSVファイルは下記の通り。

list_tab.csv

num     name
1       taro
2       "yamada,hanako"

Ruby1.8で上記コードを実行すると、以下のようにIllegalFormatErrorが出るので注意が必要(irbで実行した結果)。Ruby1.8では、セパレーターや囲み文字等をサポートしていないようである。セパレーターや囲み文字をRuby1.8で指定したい場合は、後述のFasterCSVライブラリーを使えばよい。

>> CSV.foreach("list_tab.csv", {:encoding => "UTF-8", :col_sep => "\t", :quote_char => '"' }) do |row|
?>     p row
>> end
CSV::IllegalFormatError: CSV::IllegalFormatError
    from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/csv.rb:639:in `get_row'
...

指定できるオプションは上記以外にもいろいろある。詳しくは下記のドキュメントを参照したほうがよいだろう。

ちなみにRuby1.8のCSVライブラリーのドキュメントはこちら。foreachメソッドの項目をみるとRuby1.9で指定できるオプションがない。

3. FasterCSVライブラリーを利用する方法

FasterCSVはRubyに標準で組み込まれていないライブラリーなので、使用するには別途gemでインストールする必要がある。 インストール方法は下記の通り。ただし、Ruby1.9以降はFasterCSVが標準のCSVライブラリーになっているそうなのでインストールは不要。というか、前述の「2. Ruby標準のCSVライブラリーを利用する方法」をとればよい。

# gem install fastercsv

使い方は下記の通り。 ヘッダーの有無や、文字コード、囲み文字などを指定できる。デフォルトのセパレーターはカンマ(,)である。

require 'fastercsv'
FasterCSV.foreach("list.csv", {:headers => true, :encoding => "UTF-8", :quote_char => '"'}) do |row|
    p row
    puts row[0] # 一番目の要素にアクセス
    puts row.field("name")  # ヘッダー名で要素にアクセス
end

rowに入る内容はFasterCSV::Rowオブジェクトである。普通に配列のようにアクセスできるし、ヘッダーの名前を使ってもアクセスが可能(ただしheadersオプションをtrueに設定したときのみ)。

出力例

#<FasterCSV::Row "num":"1" "name":"taro">
1
taro
#<FasterCSV::Row "num":"2" "name":"yamadao,hanako">
2
yamadao,hanako

なお、FasterCSVのドキュメントはこちら。

まとめ

いろいろ書いたが、使い方のまとめ。 単純なCSVデータであれば普通のファイル入出力のメソッドでopenしてデータをお手軽に処理すればよいと思う。 文字コードやセパレーター等を指定する必要のある複雑なデータを扱うのであればRuby1.9以降の場合は標準のCSVライブラリー、Ruby1.8の場合はFasterCSVを使うということになりそうだ。 うーん、Rubyのバージョンによって使い方を変える必要があるのは紛らわしい。 使い方をまとめて良かった。