Ruby1.9.0 のデフォルトエンコーディング
ちょっと自分用のメモ。 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'