読者です 読者をやめる 読者になる 読者になる

プログラマでありたい

おっさんになっても、プログラマでありつづけたい

Ruby2.0の文字エンコーディングの簡単なまとめ。KconvとM17N

 浦島太郎状態になっていたので、Ruby周りの文字コードの扱いについて改めて勉強しなおしました。簡単にいうとRuby 1.9.1以降の多言語化仕様(M17N)では、文字コードをどう扱えばよいのかという点です。

Rubyの文字コード変換ライブラリ


 Ruby 1.9.1の多言語仕様化以前は、文字コードの変換には文字コード変換ライブラリを使用する方法が一般的でした。主な文字コード変換ライブラリは、次のようなものがあります。

  • Kconv
  • NKF
  • Iconv
  • Uconv

 この中で、KconvはNKFのラッパーであり、NKFはnkf(Network Kanji code conversion Filte)をRubyから使うためのモジュールです。つまり実装としては、KconvとNKFの根の部分は同じです。またIconvは、UNIX95のiconv()関数のラッパーです。なお、IconvはRuby 1.9から非推奨、Ruby 2.0から標準添付ライブラリから削除されています。

Kconvの利用


 Kconvを読み込むと、Stringクラスに次のメソッドが追加されます。

String#iseuc String#isjis String#issjis String#isutf8 String#kconv String#toeuc String#tojis String#tolocale String#tosjis String#toutf16 String#toutf32 String#toutf8

使い方としては、下記のとおりで手軽に使えて便利です。

require 'kconv'

str = '日本語の文字コード'     # 何らかの文字コードの文字列
puts str.toeuc   # => ECUの文字コードに変換
puts str.tosjis  # => Shift_JISの文字コードに変換
puts str.toutf8  # => UTF-8の文字コードに変換

 一方で、Kconvについては幾つかの問題点があります。1つは、先述のとおりnkfライブラリを利用する為に、プラットフォーム依存が強いという点です。2つ目は、nkfライブラリの名前(Network Kanji code conversion Filte)が示すように、多言語化対応ではなく日本語対応のモジュールということです。この辺りの改善のために、Ruby 1.9からはM17Nを盛り込んだ仕様になっています。

追記:2014/04/08
 nkfライブラリのプラットフォーム依存の話は、間違いでした。nkfのソース自体がRubyにインポートされて、ビルドされている模様です。モジュールを確認するとその通りでした。@yugui さんご指摘ありがとうございます。

f:id:dkfj:20140408120732p:plain

$ tree nkf/
nkf/
├── Makefile
├── depend
├── extconf.h
├── extconf.rb
├── lib
│   └── kconv.rb
├── mkmf.log
├── nkf-utf8
│   ├── config.h
│   ├── nkf.c
│   ├── nkf.h
│   ├── utf8tbl.c
│   └── utf8tbl.h
├── nkf.c
└── nkf.o

M17N対応



 Ruby 1.9.1からは、M17N(Multilingualization)で多言語化の対応が根本的に変わっています。 Rubyの多言語化は、CSI(Code Set Independent)という方式を採用しています。これは他の言語の主流であるUCS Normalizationとは全く別の方式です。UCS Normalizationは、内部コードを特定の文字コード(多くの場合は、UTF)とし、入出力の際に別の文字コードが来た場合は変換して利用します。
 これに対して、Rubyが採用したCSI方式は内部コードを持ちません。どの文字コードでも、そのエンコーディングに従い扱います。そのために、プログラム自身にエンコーディングを教える必要があります。Ruby 1.9でコード中にマルチバイト文字が出てきた場合に、Magic Commentが必要になったのはこのためです。

# coding: UTF-8

str = '日本語の文字コード'     # 何らかの文字コードの文字列
puts str.encode("Shift_JIS") # => 暗黙的にUFT8から、Shift_JISに変換する
puts str.encode("Shift_JIS","UTF-8") # => 明示的にUFT8から、Shift_JISに変換する

 このString#encodeメソッドの実装は、class Encodingです。これは内部に文字コードの変換表を持っている訳ではなく、文字コードの取扱ルールを定義しているようです。またNKFのように日本語対応のみでなく、多言語対応です。

まとめ



 ということで互換性の問題がなければ、String#encodeメソッドを利用しましょう。またちゃんと、Magic Commentを書きましょうね。(Ruby 2.0ではデフォルトがUTF-8になっているので、ほぼ不要とも言えますが。)


参照:
module NKF
library kconv
Rubyist Magazine - Ruby M17N の設計と実装
class String
class Encoding::Converter
多言語化
Rubyist Magazine - 標準添付ライブラリ紹介 【第 3 回】 Kconv/NKF/Iconv
404 Blog Not Found:ruby|perl - 文字コードのちょっと高度な判定


プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)