Ruby標準ライブラリのcsvを使ったCSV操作で、個人的によく使うものを整理した。
次のfuture_gadgets.csv
という名称のCSVファイルを例として使う。
number,name,function
1号機,ビット粒子砲,おもちゃの光線銃にテレビのリモコンを合体させたもの
2号機,タケコプカメラー,軸の部分に小型カメラを仕込んだ竹トンボ
3号機,もしかしてオラオラですかーっ!?,ウソ発見器と称した発汗検知装置
出典: https://ja.wikipedia.org/wiki/STEINS;GATEの用語一覧
CSVファイルから1行ずつ読み取りたい
CSV#foreach
を使う。
1行は1つの配列として表現される。
require 'csv'
CSV.foreach('/path/to/future_gadgets.csv') do |fg|
# fgはArrayクラス
puts "[#{fg[0]}] #{fg[1]}: #{fg[2]}"
end
1行ずつ処理をするため、行数が多いCSVファイルを扱う場合でもメモリ使用量を気にしないで使える。
[number] name: function
[1号機] ビット粒子砲: おもちゃの光線銃にテレビのリモコンを合体させたもの
[2号機] タケコプカメラー: 軸の部分に小型カメラを仕込んだ竹トンボ
[3号機] もしかしてオラオラですかーっ!?: ウソ発見器と称した発汗検知装置
CSVファイルから1度に読み込みたい
CSV#read
を使う。
1行は1つの配列として表現され、全体として配列の配列が返り値となる。
require 'csv'
future_gadgets = CSV.read('/path/to/future_gadgets.csv')
future_gadgets.each do |fg|
# fgはArrayクラス
puts "[#{fg[0]}] #{fg[1]}: #{fg[2]}"
end
[number] name: function
[1号機] ビット粒子砲: おもちゃの光線銃にテレビのリモコンを合体させたもの
[2号機] タケコプカメラー: 軸の部分に小型カメラを仕込んだ竹トンボ
[3号機] もしかしてオラオラですかーっ!?: ウソ発見器と称した発汗検知装置
CSV文字列から読み取りたい
ファイルではなく文字列としてのCSVを受け取りたい場合は、CSV#parse
を使う。
CSV#foreach
と同じく、ブロックには行が配列として渡される。
require 'csv'
CSV.parse('foo,bar,baz') do |fg|
puts fg[0] # => 'foo'
puts fg[1] # => 'bar'
puts fg[2] # => 'baz'
end
ヘッダのフィールド名をキーにして操作したい
CSV.foreach
やCSV.parse
の第2引数にはHash形式でオプションを渡すことができ、ここにheaders: true
を与えることで、先頭行をヘッダして読み取ってくれるようになる。
これにより、ブロックに渡されるオブジェクトのクラスがArray
からCSV::Row
になる。
CSV::Row
はフィールド名をキーとして使えるようになるのでコードが読みやすくなる。
require 'csv'
CSV.foreach('/path/to/future_gadgets.csv', headers: true) do |fg|
# fgはCSV::Row
puts "[#{fg['number']}] #{fg['name']}: #{fg['function']}"
end
[1号機] ビット粒子砲: おもちゃの光線銃にテレビのリモコンを合体させたもの
[2号機] タケコプカメラー: 軸の部分に小型カメラを仕込んだ竹トンボ
[3号機] もしかしてオラオラですかーっ!?: ウソ発見器と称した発汗検知装置
空行を読み飛ばしたい
skip_blanks: true
をオプションとして渡す。
指定しない場合空行は空の配列などになるが、このオプションを指定することでスキップできる。
require 'csv'
CSV.foreach('/path/to/future_gadgets.csv', skip_blanks: true) do |fg|
# ...
end
空行があるとエラーになってしまったり面倒なチェック処理が必要になる場合が多いので、とりあえず指定することが多い。
TSVを読み取りたい
RubyのCSVライブラリは、名前からCSVしか操作できないような印象を受けるがそうではない。
col_sep
オプションで区切り文字を自由に設定できるので、TSVでも同じように扱うことができる。
require 'csv'
CSV.foreach('/path/to/future_gadgets.tsv', col_sep: "\t") do |fg|
# ...
end