CSV 3.1.6 がリリースされました。
CSV 3.1.6 には、CSV.open
に不正なバイトを置換文字で置き換えるオプションを追加するのに送ったパッチが取り込まれているのでその紹介です。
ユースケースとして、MS Excel 向けのエンコーディング (有名な CP932
) に変換して CSV 出力するに際して、例えば Rails アプリケーションのバリデーション不足などで含まれてしまった不正なバイトをハンドリングしたいケースに活用できるオプションです。
CSV.open(..., invalid: :replace)
指定しているエンコーディング (ここでは CP932
) へ変換できないバイトが含まれている場合、不正なバイトを置換文字で置き換えるという:invalid => :replace
オプションが File.open
にあります。CSV 3.1.5 までは CSV.open
では受け付けないオプションだったため、例えば以下のように指定する必要がありました。
File.open(filename, 'w', encoding: Encoding::CP932, invalid: :replace, undef: :replace) do |file| csv = CSV.new(file, encoding: Encoding::CP932) csv << ... csv.close end
CSV 3.1.6 から CSV.open
で :invalud
オプションを受け付けるようになったため、以下のように書くことができます。
CSV.open(filename, 'w', encoding: Encoding::CP932, invalid: :replace) do |csv| csv << ... end
対応したパッチは以下です。
また、Encoding::InvalidByteSequenceError
が起きるようなエンコーディングに対して invalid: :replace
オプション指定した場合、期待に反して ArgumentError
が起きる以下のようなコードの問題についても解消されています。
require 'csv' filename = 'foo.csv' File.open(filename, 'w', encoding: Encoding::CP932, invalid: :replace) do |file| CSV.open(filename, encoding: Encoding::CP932) do |rows| rows << ["\x82\xa0"] end end
これは上記のようなコードを書いていたとしても CSV 3.1.5 までは以下のエラーになっていたものです。
% ruby /tmp/csv.rb Traceback (most recent call last): 10: from /tmp/csv.rb:5:in `<main>' 9: from /tmp/csv.rb:5:in `open' 8: from /tmp/csv.rb:6:in `block in <main>' 7: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv.rb:658:in `open' 6: from /tmp/csv.rb:7:in `block (2 levels) in <main>' 5: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv.rb:1230:in `<<' 4: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv/writer.rb:46:in `<<' 3: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv/writer.rb:46:in `collect' 2: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv/writer.rb:47:in `block in <<' 1: from /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv/writer.rb:159:in `quote' /Users/koic/.rbenv/versions/2.7.1/lib/ruby/2.7.0/csv/writer.rb:159:in `match?': invalid byte sequence in UTF-8 (ArgumentError)
対応したパッチは以下です。
CSV.open(..., undef: :replace)
こちらも CSV 3.1.6 で以下のように File.open
の undef: :replace
オプションを CSV.open
に指定することができるようになったので、簡潔に対応できるようになりました。
CSV.open(filename, 'w', encoding: Encoding::CP932, undef: :replace) do |csv| csv << ... end
対応したパッチは以下です。
CSV gem は Gemify されているため、Ruby のアップデートと独立して bundle update
できます。詳しくは以下のエントリを参照してください。