railsでの、文字コード変換で発生する特定文字列の例外対処


CSVダウンロードの実行でUTF-8からsjis変換時に例外が発生。

いわゆる波ダッシュ問題の対応方法備忘録。

環境

$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]

$ rails -v
Rails 5.0.0.1

helperを実装

application_helper に変換用のメソッドを追加。

app/helpers/application_helper.rb
module ApplicationHelper
  # 文字コード変換用のリスト
  FROM_CHR_UTF8 = "\u{301C 2212 00A2 00A3 00AC 2013 2014 2016 203E 00A0 00F8 203A}".freeze
  # 〜−¢£¬–—‖‾ ø›
  TO_CHR_SJIS   = "\u{FF5E FF0D FFE0 FFE1 FFE2 FF0D 2015 2225 FFE3 0020 03A6 3009}".freeze
  # ~-¢£¬-―∥ ̄ Φ〉

  # UTF-8をSJIS変換時に、変換できない文字を変換できる文字に置換する。
  def sjisable(str)
    return if str.blank?
    str.tr!(FROM_CHR_UTF8, TO_CHR_SJIS)

    # 指定した文字から漏れた変換できない文字は、「?」に置換する。
    str.encode(Encoding::SJIS, Encoding::UTF_8, invalid: :replace, undef: :replace).encode(Encoding::UTF_8, Encoding::SJIS)
  end
end

使用


sjisable(string)

確認

str = '〜−¢£¬–—‖‾ ø›'
p str
p sjisable(str)
# => 〜−¢£¬–—‖‾ ø›
# => ~-¢£¬-―∥ ̄ Φ〉

p sjisable('ä啟')
# => ??

追伸

  • 文字列を渡すのではなく、配列をまるっとわたせるメソッドの方が、CSVを扱うには有用で、カラム追加時等でもバグ生みにくいか。
  • 変換のセットをhashで持つほうが保守性高そう。

参考