LoginSignup
0
0

More than 1 year has passed since last update.

RubyでCSV操作する

Last updated at Posted at 2022-09-18

前提

読み込み

仕様としては、RFC4180 に準拠している
※ 例えば、フィールドをクォートで囲むことで、カンマを含んだ文字列を扱える等が定義されている

また、バリデーションは必要に応じて別途行うこと
例. raise MalformedCSVError if csv.first != CSV_HEADERS

ファイルから

一行ずつ

CSV.open(file_path, 'r').each do |row|
  p row
end
# 結果
# [...]
# [...]
# ...
# => nil

CSV.foreach(file_path) do |row|
  p row
end
# 結果
# [...]
# [...]
# ...
# => nil

# headers オプションに偽でない値を指定した場合、CSV::Table を返す
CSV.read(file_path, headers: true).each do |row|
  p row
end
# 結果
# #<CSV::Row>
# #<CSV::Row>
# ...
# => #<CSV::Table>

# CSV.read(file_path, { headers: true, converters: :numeric, header_converters: :symbol }.merge(options)) と同じ
CSV.table(file_path).each do |row|
  p row
end
# 結果
# #<CSV::Row>
# #<CSV::Row>
# ...
# => #<CSV::Table>

まとめて

CSV.open(file_path, 'r').to_a
# 結果
# [[...], [...], ...]

CSV.read(file_path)
# 結果
# [[...], [...], ...]

※ BOM 付き CSV の場合

CSV.open('test.csv', 'rb:BOM|UTF-8')

文字列から

# 準備
csv_text = <<EOS
id,first name,last name,age
1,taro,tanaka,20
2,jiro,suzuki,18
EOS

一行ずつ

CSV.parse(csv_text) do |row|
  p row
end
# 結果
# ["id", "first name", "last name", "age"]
# ["1", "taro", "tanaka", "20"]
# ["2", "jiro", "suzuki", "18"]
# => 62

まとめて

CSV.parse(csv_text)
# 結果
# => [["id", "first name", "last name", "age"], ["1", "taro", "tanaka", "20"], ["2", "jiro", "suzuki", "18"]]

オプション

一覧のうち、よく使うものを抜粋

  • ヘッダー
    • 存在する場合は、headers: true
    • ~['カラム名']で参照できるようになる
    • 変換する場合は、header_converters: ~
      • 変換例
        • 文字列 → シンボル: :symbol
        • 独自設定: ->(h) { HEADER_MAPS[h] }
          • HEADER_MAPS = { 'a' => :a, 'b' => :b }
  • 区切り文字
    • タブ区切りにしたい時は、col_sep: "\t"
  • 文字コード
    • 変換する例: encoding: 'CP932:UTF-8'
  • 不正CSV(RFC 4180 に違反)
    • 具体的には、フィールド内にエスケープされていない二重引用符を含むケース
    • パースする場合は、liberal_parsing: true
      • 例. CSV.parse('a,b"c,d', liberal_parsing: true) => [["a", "b\"c", "d"]]
    • 解説記事

書き込み

※ 基本的にTSVで出力するようにしている
スプレッドシートに貼り付けて列分解する時に、列値にカンマ入っていると列がズレるため(列値にタブ入っていたら同じか。。スプレッドシート側の問題か)

ファイルへ

CSV.open("path/to/file.csv", "w") do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
  # ...
end

※ BOM 付き CSV の場合

文字列へ

csv_string = CSV.generate do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
end
# 結果
# => "row,of,CSV,data\nanother,row\n"

オプション

よく使うものを抜粋
読み込みと同じ場合は省略

  • ヘッダー
    • 出力する場合は、write_headers: true, headers: [...]
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0