Ruby 1.9 m17n リファレンス (不完全版)

以前書いた記事(Ruby 1.9 の新機能を調べてみた)の m17n がらみの箇所についてコメントやらトラックバックやらをいただいたので、もう少し調べてまとめてみた。
なお、1.9.0 リリース版ではなく、開発版(trunk r14835)で動作を確認している。

コマンドラインオプション

マジックコメント

  • # -*- encoding: <エンコーディング名> -*-
  • # -*- coding: <エンコーディング名> -*-
    • スクリプトファイルの1行目(1行目が shebang(#!) で始まっている場合は 2 行目)に "# -*- encoding: エンコーディング名 -*-" のようにコメントを書くとそのファイルのエンコーディングを指定できる。
    • encoding:coding: でも動作は全く同じ。((余談。今のところ、マジックコメントで指定可能なのは "encoding" と "coding" の 2 つだけ(parser.y の magic_comments)。将来的には何か増えるのかも?))
    • スクリプトエンコーディングを変更すると、以下の点が変わる。(他にもあるかも)
    • エンコーディングの設定はファイルごとに独立しており、requireload したファイルには影響を与えない。

Encoding クラス

p Encoding.list #=> [#<Encoding:ASCII-8BIT>, #<Encoding:EUC-JP>, #<Encoding:Shift_JIS>, #<Encoding:UTF-8>, #<Encoding:ISO-2022-JP (dummy)>, #<Encoding:Windows-31J>]
  • Encoding.default_external
    • IO オブジェクトから読み出しを行なう際のデフォルトの外部エンコーディング(external encoding)。
    • IO オブジェクトへの書き込みには使われない。
    • コマンドラインオプションから設定できる。
    • コマンドラインオプションでの指定が無い場合、Encoding.locale_charmap (後述)を元に設定される。
  • Encoding.find(name)
    • name というエンコーディング名の Encoding オブジェクトを探して返す。
    • 見付からない場合は ArgumentError が発生。
  • Encoding.compatible?(str1, str2)
    • 2つの文字列オブジェクトを比較し、結合可能(str1.concat(str2) が可能)なら結合後の Encoding を返す。結合不可能なら nil を返す。
  • Encoding.locale_charmap
    • システム(OS)で使われている文字セット情報を文字列で返す。(Unix 環境なら LANG とか LC_CTYPE で設定してあるもの)
    • 何が返ってくるかは OS などの環境依存。
  • Encoding#name
  • Encoding#to_s
  • Encoding#dummy?
  • Encoding#base_encoding
    • ベースとなった Encoding オブジェクトを返す。
p Encoding.find('Windows-31J')                #=> #<Encoding:Windows-31J>
p Encoding.find('Windows-31J').base_encoding  #=> #<Encoding:Shift_JIS>

String クラス

  • 全般
  • String#[], etc.
    • インデックスが文字単位になり、返り値は String になった。(さんざん既出)
  • String#size
  • String#length
    • 文字数を返す。
  • String#bytesize
    • バイト数を返す。
  • String#each_byte
  • String#each_char
  • String#each_line
    • 文字列をそれぞれバイト単位、文字単位、行単位に分解してブロックを呼び出す。
    • ブロックを省略すると Enumerator を返す。(ruby 1.9 ではおなじみの動作)
  • String#bytes
  • String#chars
  • String#lines
    • #each_byte, #each_char, #each_line の別名。
  • String#ord
    • 1文字目の文字コードを返す。
    • 1文字目が UTF-8 な多バイト文字の場合、UTF-8 デコードされた結果の Unicode コードポイント値が返る。(string.unpack('U').first と同じ)
    • 1文字目が Shift_JIS または EUC-JP な 2 バイト文字の場合、1 文字目の文字コードが返る。(string[0].unpack('n').first と同じ)
  • String#encoding
  • String#encode(enc)
  • String#encode(to_enc, from_enc)
  • String#encode!(enc)
  • String#encode!(to_enc, from_enc)
    • String#encode の破壊的メソッド版。
    • 変換後の文字列(自分自身)を返す。
  • String#force_encoding(encoding)
    • 文字列のエンコーディングを変更する。バイト列は変更されない。
    • 文字列(自分自身)を返す。
  • String#valid_encoding?
    • その文字列が正しいエンコーディングかどうか(文字列として正しいバイト表現なのかどうか)を true または false で返す。
  • String#concat
  • String#<<
  • String#+
ascii = 'a'.force_encoding('ASCII')
utf8  = ''.force_encoding('UTF-8')
p (ascii + utf8).encoding  #=> #<Encoding:UTF-8>

Regexp クラス

p //u.encoding #=> #<Encoding:UTF-8>
    • 互換性の無いエンコーディングを持った文字列とマッチングを行なった場合は ArgumentError が発生。
//u.match("\xa4\xa2".force_encoding('EUC-JP')) #=> ArgumentError: incompatible encoding regexp match (UTF-8 regexp with EUC-JP string)
  • Regexp#encoding
  • Regexp#fixed_encoding?
    • 正規表現がどんな文字列とでもマッチング可能なら false、それ以外(互換性の無いマッチングとして ArgumentError が起こりうるような正規表現)なら true。
p /a/n.fixed_encoding?  #=> false
p //u.fixed_encoding? #=> true

IO クラス

$stdin.set_encoding('UTF-8:Shift_JIS')  #=> #<IO:<STDIN>>
p $stdin.internal_encoding     #=> #<Encoding:Shift_JIS>
p $stdin.external_encoding     #=> #<Encoding:UTF-8>
p Encoding.default_external  #=> #<Encoding:UTF-8>
open('filename', 'r') do |f|
  p f.internal_encoding      #=> nil
  p f.external_encoding      #=> #<Encoding:UTF-8>
  p f.read.encoding          #=> #<Encoding:UTF-8>
end
open('filename', 'r:EUC-JP') do |f|
  p f.internal_encoding      #=> nil
  p f.external_encoding      #=> #<Encoding:EUC-JP>
  p f.read.encoding          #=> #<Encoding:EUC-JP>
end
      • IO#internal_encodingnil 以外の場合、読み出した文字列を external_encoding から internal_encoding に変換した結果が返る。
p Encoding.default_external  #=> #<Encoding:UTF-8>
open('filename', 'r:EUC-JP:UTF-8') do |f|
  p f.internal_encoding      #=> #<Encoding:UTF-8>
  p f.external_encoding      #=> #<Encoding:EUC-JP>
  p f.read.encoding          #=> #<Encoding:UTF-8>
  # ↑ここで EUC-JP から UTF-8 へ変換
end
    • 書き込み時
      • IO#internal_encodingIO#external_encoding がともに nil の場合、エンコーディングの変換(transcode)は行なわれずにそのまま出力される。(デフォルト動作)
      • IO#internal_encodingnilIO#external_encoding が設定されている場合、文字列のエンコーディングexternal_encoding に変換した結果を出力する。(内部では String#encode が呼ばれる)
str = "\xa4\xa2".force_encoding('EUC-JP')  # EUC-JP で 'あ'
p $stdout.internal_encoding        #=> nil
p $stdout.external_encoding        #=> nil
$stdout.set_encoding('UTF-8')
p $stdout.internal_encoding        #=> nil
p $stdout.external_encoding        #=> #<Encoding:UTF-8>
puts str   #=> あ
# ↑ここで EUC-JP から UTF-8 へ変換
      • IO#internal_encodingIO#external_encoding がともに設定されている場合、文字列が持っているエンコーディング情報に関わらず、エンコーディングinternal_encoding から external_encoding へ変換した結果を出力する。(内部では String#encode が呼ばれる)
str = "\xa4\xa2".force_encoding('ASCII')  # EUC-JP で 'あ'
$stdout.set_encoding('UTF-8', 'EUC-JP')
p $stdout.internal_encoding       #=> #<Encoding:EUC-JP>
p $stdout.external_encoding       #=> #<Encoding:UTF-8>
p str.encoding                    #=> #<Encoding:ASCII-8BIT>
puts str   #=> あ
# ↑ここで EUC-JP から UTF-8 へ変換


まだ理解してない部分、抜けてる部分、挙動が確定してなさそうな部分(バイナリモードの IOエンコーディング指定するとどうなるの? とか)があるので、気づいたら徐々に穴埋めするかも。

  • 2008/01/04 説明文を修正。