LoginSignup
70
63

More than 5 years have passed since last update.

Windows-31Jに変換する時の例外を防止するためのString拡張

Posted at

String拡張

class String
  def sjisable
    str = self
    #変換テーブル上の文字を下の文字に置換する
    from_chr = "\u{301C 2212 00A2 00A3 00AC 2013 2014 2016 203E 00A0 00F8 203A}"
    to_chr   = "\u{FF5E FF0D FFE0 FFE1 FFE2 FF0D 2015 2225 FFE3 0020 03A6 3009}"
    str.tr!(from_chr, to_chr)
    #変換テーブルから漏れた不正文字は?に変換し、さらにUTF8に戻すことで今後例外を出さないようにする
    str = str.encode("Windows-31J","UTF-8",:invalid => :replace,:undef=>:replace).encode("UTF-8","Windows-31J")
  end
end

テスト

#変換テーブル上の文字が置換されていることを確認
from_chr = "\u{301C 2212 00A2 00A3 00AC 2013 2014 2016 203E 00A0 00F8 203A}"
p from_chr    
p from_chr.sjisable

#Shift_JISにもWindows-31Jにもない文字は諦めて?にする
p "ä".sjisable

# Windows拡張領域は保持されていることを確認
p "①②③髙島屋".sjisable

実行結果

スクリーンショット 2014-11-15 13.16.58.png

これどんないいことがあるの?

Rubyの内部コードはもはやUTF8。だけど、最終的にはエクセル向けにシフトJISのCSVを出力することもある。だけど、内部コードから出力時にエンコード変換をすると、対応する文字が見つからなくて、例外がでちゃう。例外はヤなので、多少は文字を置き換え(もしくは全く変換できないものは?に置換)してでも、処理を通したいということはある。

解説

Rubyでは、シフトJIS系のエンコード名には以下の種類がある。
* Shift_JIS
* Windows-31J
* SJIS(これはWindows-31Jのエイリアス)
* CP932(これはWindows-31Jのエイリアス)
SJISとCP932はエイリアスなので、実際はShift_JISとWindows-31Jの二つであると思っていい。
例えば、~という文字は、Shift_JISでもWindows31Jでも、コードとしては、「8160」が割り当てられえている。
* 8160をShift_JISとしてUNICODEに変換すると301C(波ダッシュ)
* 8160をWindows31JとしてUNICODEに変換するとFF5E(全角チルダ)
UNICODEは扱える文字が多いから、UNICODEで保持する間は被害が少ない。辛いのは、UNICODEからShift_JISやWindows-31Jに変換するとき。Windows-31Jは波ダッシュのことは知らないし、Shift_JISは全角チルダのことなんて知らない。シフトJIS系のテキストが求められる時ってWindowsが多いので、どっちに合わせるって言えば、Windows-31Jに合わせるケースが多い。

保守

from_chrとto_chrの文字を増やしていけば、変換する文字は増やせる。trメソッドは、文字単位で置換してくれるので便利ですね。~とかはありがちなんだけど、øとかは、Shift_JISにもWinndows-31Jにも存在しないので、「近しい文字」に置換するテーブルは業務ルールで足していけばいいんじゃないですかね。

70
63
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
70
63