🐕
Rubyで波ダッシュ(〜)の文字コード変換
概要
Rubyで文字コードをUTF-8からSJISに変換したCSVを扱っている際に、波ダッシュ(〜)を含むデータがCSVに存在している場合に、期待している動作にならないことがありました。
調査をすると波ダッシュ・全角チルダ問題なるものがあると知りました。
波ダッシュ・全角チルダ問題に関しては、参考文献に記載したリンク先にとても詳しく記載されているので、そちらを参照してください。
この記事では
- そもそもSJISってなんだ?
- Rubyの各メソッドでの波ダッシュ・全角チルダの文字コード変換
という2点を記載しようと思います。
※ 以下では基本的にRubyに関連する話をするので、他の言語では事情が異なる場合があります。
そもそもSJISとは
今までSJISのことを「Shift_JISの略語」というフワッとした理解をしていたのですが、どうやら怪しそうです。
以下に記載したのですが、SJISがShift_JISを指しているものと、Windows-31JというShift_JISを拡張した文字コードを指しているものがあります。
EncodingクラスでのSJIS
EncodingクラスでのSJISはWindows-31Jを指しているようです。
[1] pry(main)> Encoding::SJIS
=> #<Encoding:Windows-31J>
NKFモジュールでのSJIS
NKFモジュールでのSJISはShift_JISを指しているようです。
[1] pry(main)> NKF::SJIS
=> #<Encoding:Shift_JIS>
波ダッシュ・全角チルダの文字コード変換
以下に波ダッシュ・全角チルダの
- Stringクラスのencodeメソッド
- NKFモジュールのnkfメソッド
での文字コード変換の結果をコードで記載しました。
個人的に曲者だなと感じたのは
- NKFモジュールのnkfメソッドで波ダッシュをUTF-8 → Windows-31J変換した際に空白文字になる
- 波ダッシュをWindows-31J → UTF-8変換した際に全角チルダになる
という2点でした。
UTF-8 → Shift_JIS, Windows-31J
Stringクラスのencodeメソッドでの変換
[1] pry(main)> "〜".encode("Shift_JIS") # 波ダッシュ
=> "\x{8160}" # 波ダッシュ
[2] pry(main)> "~".encode("Shift_JIS") # 全角チルダ
Encoding::UndefinedConversionError: U+FF5E from UTF-8 to Shift_JIS
from (pry):2:in `encode'
[3] pry(main)> "〜".encode("Windows-31J") # 波ダッシュ
Encoding::UndefinedConversionError: U+301C from UTF-8 to Windows-31J
from (pry):3:in `encode'
[4] pry(main)> "~".encode("Windows-31J") # 全角チルダ
=> "\x{8160}" # 波ダッシュ
NKFモジュールのnkfメソッドでの変換
[1] pry(main)> NKF.nkf("--oc=Shift_JIS", "〜") # 波ダッシュ
=> "\x{8160}" # 波ダッシュ
[2] pry(main)> NKF.nkf("--oc=Shift_JIS", "~") # 全角チルダ
=> "\x{8160}" # 波ダッシュ
[3] pry(main)> NKF.nkf("--oc=Windows-31J", "〜") # 波ダッシュ
=> ""
[4] pry(main)> NKF.nkf("--oc=Windows-31J", "~") # 全角チルダ
=> "\x{8160}" # 波ダッシュ
Shift_JIS, Windows-31J → UTF-8
Stringクラスのencodeメソッドでの変換
[1] pry(main)> "\x81\x60".encode("UTF-8", "Shift_JIS").unpack1('U*').to_s(16)
=> "301c" # 波ダッシュ
[2] pry(main)> "\x81\x60".encode("UTF-8", "Windows-31J").unpack1('U*').to_s(16)
=> "ff5e" # 全角チルダ
NKFモジュールのnkfメソッドでの変換
[1] pry(main)> NKF.nkf("--ic=Shift_JIS --oc=UTF-8", "\x81\x60").unpack1('U*').to_s(16)
=> "301c" # 波ダッシュ
[2] pry(main)> NKF.nkf("--ic=Windows-31J --oc=UTF-8", "\x81\x60").unpack1('U*').to_s(16)
=> "ff5e" # 全角チルダ
まとめ
- SJISがShift_JISのことを指すか、Windows-31Jのことを指すか確認推奨
- 波ダッシュ・全角チルダの文字コード変換にShift_JISやWindows-31Jが関係する際は注意
参考文献
Discussion