LoginSignup
59
47

More than 5 years have passed since last update.

CSV.open で Encoding::UndefinedConversionError になる場合

Last updated at Posted at 2014-06-06

Ruby 標準添付ライブラリの CSV で Windows-31J (Shift_JIS でも良いけど) な CSV を作っていたのだけれども、特定の文字が含まれていると Encoding::UndefinedConversionError になってしまう。

irb(main):011:0> CSV.open(File.join('/var/tmp/hoge.csv'), 'w', encoding: 'Windows-31J') do |csv|
irb(main):012:1*   csv << %w( d é f )
irb(main):013:1> end
Encoding::UndefinedConversionError: U+00E9 from UTF-8 to Windows-31J

最初は気楽に undef とか replace とか指定すれば良いんでしょ、とか思っていたんだけど。

irb(main):014:0> CSV.open(File.join('/var/tmp/hoge.csv'), 'w', encoding: 'Windows-31J', undef: :replace, replace: '*') do |csv|
irb(main):015:1*   csv << %w( d é f )
irb(main):016:1> end
ArgumentError: Unknown options:  undef, replace.

CSV.open に undef も replace も渡せない。
(話の流れで省略してるけど invalid も同じように渡せない)

実際に例外出しているのは CSV.new で、 CSV.new には決まったオプションしか渡せない。

書き出しの手間を考えると CSV ライブラリは使いたい、でも undef, replace 使いたい。
でも CSV.new には undef とか渡せない、でも文字コード変換して CSV 書き出したい。
とかぐるぐるしてたんだけれども。

実際に CSV.open が何をやっているかを参考にしつつ。
File.open して、それを CSV.new に渡すことにした。

irb(main):017:0> File.open(File.join('/var/tmp/hoge.csv'), 'w', encoding: 'Windows-31J', undef: :replace, replace: '*') do |file|
irb(main):018:1*   csv = CSV.new(file, encoding: 'Windows-31J')
irb(main):019:1>   begin
irb(main):020:2*     csv << %w( d é f )
irb(main):021:2>   ensure
irb(main):022:2*     csv.close
irb(main):023:2>   end
irb(main):024:1> end
=> <#CSV io_type:File io_path:"/var/tmp/hoge.csv" encoding:Windows-31J lineno:1 col_sep:"," row_sep:"\n" quote_char:"\"">

これで、例外にならない。

$ cat /var/tmp/hoge.csv
d,*,f

指定の通りに replace されてる。

59
47
2

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
59
47