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
)。将来的には何か増えるのかも?))- スクリプトのエンコーディングを変更すると、以下の点が変わる。(他にもあるかも)
- エンコーディングの設定はファイルごとに独立しており、
require
やload
したファイルには影響を与えない。
- スクリプトファイルの1行目(1行目が shebang(
Encoding クラス
- エンコーディング名
- 有効なエンコーディング名は "
ASCII
", "UTF-8
", "EUC-JP
", "Shift_JIS
", "ISO-2022-JP
", "Windows-31J
", "ISO-8859-1
" など。 - 幾つかの別名も登録されている。"
US-ASCII
", "ASCII-8BIT
", "BINARY
", "eucJP
", "SJIS
", "CP932
" など。 - エンコーディング名は大文字・小文字を区別しない。(case insensitive)
- 有効なエンコーディング名は "
Encoding.list
- ロード済みの
Encoding
の一覧をArray
で返す。 - 各エンコーディングは必要に応じて自動的にロードされる。
- ロード済みの
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
Encoding.find(name)
name
というエンコーディング名のEncoding
オブジェクトを探して返す。- 見付からない場合は
ArgumentError
が発生。
Encoding.compatible?(str1, str2)
- 2つの文字列オブジェクトを比較し、結合可能(
str1.concat(str2)
が可能)なら結合後のEncoding
を返す。結合不可能ならnil
を返す。
- 2つの文字列オブジェクトを比較し、結合可能(
Encoding.locale_charmap
- システム(OS)で使われている文字セット情報を文字列で返す。(Unix 環境なら
LANG
とかLC_CTYPE
で設定してあるもの) - 何が返ってくるかは OS などの環境依存。
- システム(OS)で使われている文字セット情報を文字列で返す。(Unix 環境なら
Encoding#name
Encoding#to_s
- エンコーディング名を文字列で返す。
Encoding#dummy?
- ダミーエンコーディングであるかどうかを true または false で返す。
- 「ダミーエンコーディング」とは、
String#[]
などの文字単位の処理が正しく実装できないような(stateful な)エンコーディングのこと。(例: ISO-2022-JP)
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
String#encoding
- 文字列オブジェクトのエンコーディングを
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?
p /a/n.fixed_encoding? #=> false p /あ/u.fixed_encoding? #=> true
IO クラス
- 全般
IO.open
IO.popen
Kernel#open
- 第2引き数(mode)で、"
r:UTF-8
" または "r:UTF-8:EUC-JP
"のようにコロン区切りでエンコーディング名を指定することによりIO
オブジェクトのエンコーディングを設定できる。 - エンコーディングを1つ指定した場合、それが外部エンコーディングとして設定される。
- エンコーディングを2つ指定した場合、1つ目が外部エンコーディングとして、2つ目が内部エンコーディングとして設定される。
- 書き込みモードの時も同様に指定できる。
- 読み出しモードで外部エンコーディングを指定せずに
IO
オブジェクトを作成した場合、外部エンコーディングとしてEncoding.default_external
が設定される。IO
のサブクラスの場合は挙動が変わるかも。
- 第2引き数(mode)で、"
IO#getc
IO#ungetc
- 1文字を読み出す、または戻す。(多バイト文字も考慮される)
IO#external_encoding
IO
オブジェクトの外部エンコーディングをEncoding
で返す。- 設定していない場合は
nil
が返る。
IO#internal_encoding
IO
オブジェクトの内部エンコーディングをEncoding
で返す。- 設定していない場合は
nil
が返る。
IO#set_encoding(enc)
IO#set_encoding(ext_enc, int_enc)
$stdin.set_encoding('UTF-8:Shift_JIS') #=> #<IO:<STDIN>> p $stdin.internal_encoding #=> #<Encoding:Shift_JIS> p $stdin.external_encoding #=> #<Encoding:UTF-8>
- エンコーディング変換 (transcode)
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_encoding
がnil
以外の場合、読み出した文字列を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
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 へ変換
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 へ変換
- TODO
- 一旦設定した外部/内部エンコーディングを
nil
に戻すことはできるか?
- 一旦設定した外部/内部エンコーディングを
まだ理解してない部分、抜けてる部分、挙動が確定してなさそうな部分(バイナリモードの IO
でエンコーディング指定するとどうなるの? とか)があるので、気づいたら徐々に穴埋めするかも。
- 2008/01/04 説明文を修正。