Ruby1.9.0 のデフォルトエンコーディング
2008-01-06
ちょっと自分用のメモ。 Ruby1.9.0 で起動時の —encoding オプションをいろいろ変えてみた。
# (1) デフォルトエンコーディング
puts Encoding.default_external
# (2) 生成した文字列のエンコーディング
puts "".encoding
# (3) 外部から入力した文字列のエンコーディング
ARGF.each{|v| puts v.encoding }
結果は以下の通り。
encodingオプション | (1) デフォルト | (2) 生成した文字列 | (3) 外部から入力した文字列 |
EUC-JP | EUC-JP | ASCII-8BIT | EUC-JP |
Binary | ASCII-8BIT | ASCII-8BIT | ASCII-8BIT |
何が言いたいかというと、 —EUC-JP オプションを付けた場合に、以下のコードがエラーになるということ。 これは、 tDiary2.2 の plugin/00default.rb から抜粋してる。
r = ''
r << <<-FORM
<div class="caption"><a name="c">#{comment_description}</a></div>
<form class="comment" name="comment-form" method="post" action="#{h @index}"><div>
FORM
なぜダメかというと、 —encoding=EUC-JP とした場合に、変数 r は ASCII-8BIT としてみなされるけど、外部入力である comment_description は EUC-JP とみなされる。 異なるエンコーディング同士の結合なので、「character encodings differ」エラーが起きるというわけ。 これが去年の日記に書いた「ツッコミを入れるとエラーになった」の原因だった。
<追記ここから> 取り消し線の箇所は誤りだった。異なるエンコーディング同士の場合は自動的にエンコードを変換してくれるようになってる。 <追記ここまで>
…と思ったけど、そう単純でもないみたい。 以下のコードは期待通りに動く。 str は ASCII-8BIT で line は EUC-JP なのに、自動的に str を EUC-JP にコンバートしてくれている。
puts Encoding.default_external
str = ''
ARGF.each{|line|
str << line
puts str
}
うーん。tDiary のほうは eval しているから?よくわかんない。
追記
原因が分かった。問題は以下の箇所だった。 デフォルトエンコーディング云々は完全に勘違い。
#{comment_name_label}:<input class="field" name="name" value="#{h( @cgi.cookies['tdiary'][0] || '' )}">
ここで、 comment_name_label の encoding は EUC-JP 。 @cgi.cookies[‘tdiary’][0] の encoding は ASCII-8BIT になってる。 ASCII-8BIT を EUC-JP に変換できなかったからエラーになってたんだ。 でも、 @cgi.cookies だけ encoding が ASCII-8BIT になっている理由はよく分からない。
やっぱり、Ruby 1.9.0 の M17N メモで書かれているように、 EUC-JP じゃなくて Binary モードの方がいいのかなぁ。
ruby 1.8 系と同じように動作させるときには、文字コードをバイナリとみなす(読み込み時に “rb” のように指定するか、 force_encoding(Encoding::Binary) を実行する)といいんじゃないかという気がする。
でも、今のソースを —encoding=Binary で動かすと、以下のエラーが出るんだよね。
character encodings differ(erb):35:in `concat'
(erb):35:in `do_eval_rhtml'
/home/machu/local/lib/ruby/1.9.0/erb.rb:744:in `eval'