約束の地

キャロ組

Ruby で UTF-8 の文字を Shift JIS の文字に変換する

発端

UTF-8 の CSV は Excel で文字化けするから。

メソッド

素晴らしいメソッドがありました。String クラスを拡張するメソッドです。

このメソッドの特徴は、「UTF-8 → Shift-JIS → UTF-8」という変換を行う点です。つまり、元々の文字の文字エンコーディングには変更がない、ということです。素的な設計だと思います。

もしShift-JISで文字列を吐き出したい場合は、この #sjisable を施した文字列を「何も考えずに」Shift-JISに変換すればいいだけとなります*1


以下は、上記の記事を発見する前の記事です(残しておきます)

メソッド(旧記載)

元々以下のページにあるものに手を加えただけです。

上記のメソッドをそのまま使っていたのですが、ある日エラーで出力が止まっていまして、エラーメッセージを見たところ以下のようなメッセージを吐いていました。

(省略)
foobar.rb:331:in `encode': U+200B from UTF-8 to Windows-31J (Encoding::UndefinedConversionError)
(省略)

U+200B って何ぞ、と思い調べてみたところ、「ゼロスペース」「幅なしスペース」「zero-width space character」とのこと。これの処理は前述のメソッドには含まれていませんでした。

結論

したがって、当該メソッドを以下のように書き換えて事なきを得ました。[(UTF-8の文字),(SJISの文字)]という並びです。

def sjis_safe(str)
  [
    ["301C", "FF5E"], # wave-dash
    ["2212", "FF0D"], # full-width minus
    ["00A2", "FFE0"], # cent as currency
    ["00A3", "FFE1"], # lb(pound) as currency
    ["00AC", "FFE2"], # not in boolean algebra
    ["2014", "2015"], # hyphen
    ["2016", "2225"], # double vertical lines
    ["200B", ""    ], # zero-width space
  ].inject(str) do |s, (before, after)|
      s.gsub(
        before.to_i(16).chr('UTF-8'),
        after.to_i(16).chr('UTF-8'),
      )
    end
end

大結論

絵文字が入ってきたりするともうどうにもならないので、Shift JIS からは原則として決別するのが良いです。

*1:美しい

Powered by はてなブログ