18
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CSV.tableでゼロ埋めされてる数値を読みこめない罠

Last updated at Posted at 2016-02-05

RubyからCSVファイルを読み込む時にCSV.tableメソッドが大変便利で愛用していたのですが、
データによっては正しく読み込めないことがあったので原因と対処をまとめます。

起きた問題

以下のようなCSVをCSV.tableで読み込んだところ、emp_noが正しく読み込まれませんでした。

sample.csv
emp_no, name
010, 栗山英樹
sample.rb
csv = CSV.table('./sample.csv', {:encoding => 'UTF-8'})
csv[:emp_no][0] #=> 8

勘の良い方ならおわかりかと思いますが、'010'という文字列が8進数の数値だと思われてしまっているようです。

原因

なんでこんなことになるかわからないので、CSV.tableのソースを見てみたら以下のようになっていました。

csv.rb
  #
  # A shortcut for:
  #
  #   CSV.read( path, { headers:           true,
  #                     converters:        :numeric,
  #                     header_converters: :symbol }.merge(options) )
  #
  def self.table(path, options = Hash.new)
    read( path, { headers:           true,
                  converters:        :numeric,
                  header_converters: :symbol }.merge(options) )
  end

要はCSV.tableは、より一般的なCSV.readに良い感じにオプションを渡しているだけのラッパーなんですね。

で、問題になるのはこのconverters: :numericの部分です。
リファレンスマニュアルのcovertersの部分を読むと以下のような記述が

:integer
Kernel.#Integer を使用してフィールドを変換します。
:float
Kernel.#Float を使用してフィールドを変換します。
:numeric
:integer と :float の組み合わせです。

Kernel.Integer は数値と判断できる文字列を整数に変換しますので、
"010"は8進数だと判断されて数値の8に変換されてしまっていた、ということです。

対処法

convertersにnumericを使わないようにオプションを指定してあげます。

sample.rb
csv = CSV.table('sample.csv', {:encoding => 'UTF-8', :converters => nil})

これで直りました。

18
12
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
18
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?