RubyでCSV読み込み(と少しハマった点のメモ)

Ruby
スポンサーリンク

簡単なスクレイピングで取得したデータをカンマ区切りのCSV形式で出力が出来たので、続けてCSVファイルを読み込んでみたところ少しハマったのでメモ。(昨日の記事の続き)

Rubyで簡単なスクレイピングをしてみる
はじめに Webサイトから情報を集めてくるスクレイピングというものを試してみる。 元ネタはgooニュースにあるタレント一覧。ここからタレント一覧を抜き出してみる。 対象とするサイトの構成を確認 はじめにインデックスページ...
スポンサーリンク

CSVファイルの読み込み

CSVファイルの読み込みには、そのものズバリ「csv」というライブラリがあるようなので、これを使ってみる。

require 'csv'
CSV.foreach("name_list.csv") do | row |
  name_list.push(row[1]) # 名前, フリガナ
end

 

読み込みエラー

すると、「CSVファイルの8911行目に変なデータがあるぞ」みたいなエラーが出て止まる。

Traceback (most recent call last):
9: from csv_read_test.rb:9:in `<main>’
8: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1141:in `foreach’
7: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1289:in `open’
6: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1142:in `block in foreach’
5: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1763:in `each’
4: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1821:in `shift’
3: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1821:in `loop’
2: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1867:in `block in shift’
1: from /Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1867:in `each’
/Users/xxx/.rbenv/versions/2.5.1/lib/ruby/2.5.0/csv.rb:1911:in `block (2 levels) in shift’: Illegal quoting in line 8911. (CSV::MalformedCSVError)

どうもダメなデータはコレみたい。

「”サイトウ”JxJx”ジュン”,”サイトウ ジェイジェイ ジュン”」

データにダブルクォート(”)を含むとダメ、というよりエスケープが必要になるのでCSV形式でファイルを書き出す際、次のようにエスケープするように変更。

name.gsub!(/\”/, ‘””‘)

これで
「”サイトウ””JxJx””ジュン”,”サイトウ ジェイジェイ ジュン”」
とダブルクォートがエスケープできたので、データを読み込み可能に。

補足1:CSVについて

CSV(comma-separated values)はカンマ区切りでデータを記述したテキストデータ。

歴史や背景なんかの詳細はWikipediaに。

Comma-Separated Values - Wikipedia

また、昔から使われているデータ形式だけど、2005年に一応?仕様化(RFC4180)されている模様。

RFC 4180 - Common Format and MIME Type for Comma-Separated Values (CSV) Files

補足2:読み込み時にオプション指定すればオッケーかも

liberal_parsing のオプションを利用すると、ダブルクォートで囲ってないデータであること前提だけど、データ中に出てくるダブルクォートは救済してもらえる模様。(とはいえ、データはRFC4180に準拠した方が良いと思うけど)

CSV.foreach(“name_list.csv”, liberal_parsing: true) do | row |
name_list.push(row[1]) # 名前, フリガナ
end

まとめ

CSVデータは手軽に作成できる一方、「とりあえずカンマ区切りにしとけば良いんでしょ」とか考えているとデータ内容次第で読み込み時にハマる可能性あり。(使用するライブラリによっても対応はまちまちっぽいので気をつけたい)
CSVを使う際には「データ自体にカンマ、ダブルクォート、改行あたりを含むかどうか」は最低限でも考慮が必要ですよ、と。

コメント