monthly gimite

試験運用中。

Ruby 1.9.1のm17nについてメモ

2009/2/8追記: 今はもう↓の公式ドキュメントやid:macksさんのドキュメントなどいろんな情報が出ているので、このメモの存在意義は微妙ですが、一応1.9.1に合わせて修正しておきました。

この辺のドキュメントが見つからず(まだない?)、いろいろ試行錯誤して分かったことをメモ。

まず、Ruby 1.9では文字列オブジェクトがそれぞれ文字コードを持っている。

p "a".encoding #=> #<Encoding:US-ASCII>

ファイルの先頭に

# -*- encoding: UTF-8 -*-

と書いておくと、文字列リテラルのencodingがUTF-8になる。

p "".encoding #=> #<Encoding:UTF-8>
p "a".encoding #=> #<Encoding:UTF-8>

これを書かずに文字列リテラルに日本語を書くとinvalid multibyte charというエラーになる(デフォルトはUS-ASCIIなので)。

[]とかのメソッドは文字単位に。

p "あいう"[0] #=> "あ"
p "あいう".size #=> 3

文字コード変換。

p "".encode("EUC-JP")

同じバイト列のままencodingを変更するにはforce_encoding。破壊的なメソッド*1なので注意。

p "\xE3\x81\x82".force_encoding("UTF-8") #=> "あ"

普通にファイルを読み込むと、encodingはEncoding.default_external(デフォルトでは、環境変数LANGなどから推定された実行環境の文字コード)になる。

open("test.txt") do |f|
  p f.external_encoding #=> #<Encoding:Windows-31J>
  p f.internal_encoding #=> nil
  p f.gets().encoding   #=> #<Encoding:Windows-31J>
end

UTF-8のファイルを読み込む(文字コード変換なし)。

open("test.txt", "r:utf-8") do |f|
  p f.external_encoding #=> #<Encoding:UTF-8>
  p f.internal_encoding #=> nil
  p f.gets().encoding   #=> #<Encoding:UTF-8>
end

Shift JISのファイルをUTF-8に変換して読み込む。

open("test.txt", "r:windows-31j:utf-8") do |f|
  p f.external_encoding #=> #<Encoding:Windows-31J>
  p f.internal_encoding #=> #<Encoding:UTF-8>
  p f.gets().encoding   #=> #<Encoding:UTF-8>
end

UTF-8をShift JISに変換してファイルに出力。

open("test.txt", "w:windows-31j:utf-8") do |f|
  f.puts("ほげ")
end

標準入力でShift JIS→UTF-8変換。

$stdin.set_encoding("Windows-31J", "UTF-8")
gets()

標準出力でUTF-8→Shift JIS変換。

$stdout.set_encoding("Windows-31J", "UTF-8")
puts("ほげ") #=> Shift JISで出力される

基本的にencodingが違う文字列を結合しようとするとエラー。

p "".encode("Shift_JIS") + "".encode("EUC-JP")
# => character encodings differ (ArgumentError)

ただしASCIIのみからなる文字列はどんな文字列*2とも結合可能。

p ("" + "a".encode("EUC-JP")).encoding #=> #<Encoding:UTF-8>

ref. Ruby 1.9 の新機能を調べてみた

*1:オブジェクト自身を書き換える、ということ。

*2:ただし、UTF-16などASCII互換でない文字コードとは連結不可。