2004年10月 8日
Ruby: 日本語の文字列を UTF-8 に変換する
日本語の文字列 (euc-jp, shift_jis, iso-2022-jp, utf-8 のいずれかわからない) を UTF-8 に変換しようと思った。
最初は samidareに含まれる Mconv.guess_charset を試したが、巨大なテキストを扱うとかなり遅かったので、ここやここやここを参考にして、次のようなコードを書いた。
class Iconv Preference = ["iso-2022-jp", 'euc-jp', 'utf-8', 'shift_jis', 'windows-31j'] def self.tou8 (str) return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # us-ascii Preference.each {|name| begin return Iconv.conv("UTF-8", name, str) rescue Iconv::IllegalSequence end } raise 'unable to convert to UTF-8' end end
Iconv につっこんでみて、エラーが起きたら次の候補を試す、という単純な仕組みである。このとき、試す順序は誤変換を防ぐために重要で、akr氏が検討を行った Mconv の順序を見習った。ただし、 glibc の iconv は厳格で、 shift_jis では丸数字などを許さないので windows-31j も加えておいた。
上のコードでは文字列のチェックを完全に iconv に頼っているので、チェックが甘い iconv だと困るかもしれない。また、Mconv.guess_charset ではちょっとくらいの間違い (euc-jp で丸数字を使っているとか) は許容するが、上のコードでは glibc の iconv を使うと厳格にはじかれてしまう。
追記: Preference の先頭から us-ascii を外して、正規表現マッチで判別するようにしました。手元の iconv では iso-2022-jp の文字列を Iconv.conv("UTF-8", "us-ascii", str) でエラーなしに無変換で通すことに気づいたためです。