2011年9月27日

[ruby-list:48418] Re: Ruby 1.9 で Shift JIS の YAML

5.5 さん

信岡です。

> ところが,Ruby 1.9 では,Shift JIS の YAML テキストを与えても,
> UTF-8 としてパースしているように見えます。
> Shift JIS として解釈させる方法がありますか?

Ruby 1.9 では、UTF-8 としてパースしているというよりも、
Ruby 1.8 と同じく文字エンコーディングを気にせずにパースして、
結果の文字列のエンコーディングを問答無用で UTF-8 に指定しているように思います。
(YAML ライブラリの中身をちゃんと見ていないので間違えているかもしれません。)
そのため、 force_encoding メソッドを使って YAML ライブラリの出力文字列のエンコーディングを
本来のエンコーディングに戻してやるという方法で使えないことはないと思います。

#! ruby1.9 -ECP932:CP932
# coding: CP932

require "yaml"
text = '- 日本語'
# YAML.load の結果が問答無用で UTF-8 になるのでエンコーディングを指定しなおす
str = YAML.load( text ).first.force_encoding( Encoding::CP932 )
puts text.encoding, #=> Windows-31J
str.encoding, #=> Windows-31J
str.size, #=> 3
str.unpack( 'C*' ).map{ |c| c.to_s( 16 ).upcase }.join( ' ' )
#=> 93 FA 96 7B 8C EA

しかしながら、Shift_JIS (または CP932) では、特定の文字の 2 バイト目が
バックスラッシュのバイト値と同じになりますので、例えば以下のような場合に
エラーが発生してしまいます。 (これは Ruby 1.8 でも 1.9 でも同様です。)

#! ruby1.8 -Ks

require "yaml"
text = '[ "噂" ]' # CP932 の '噂' の 2 バイト目はバックスラッシュと同じバイト値
str = YAML.load(text).first # エラー発生
puts text.encoding, str.encoding, str.size
puts str.unpack( 'C*' ).map{ |c| c.to_s( 16 ).upcase }.join( ' ' )

どうしても Shift_JIS を使わなければいけない、というのでないならば、
UTF-8 に変換してから YAML.load に投げる、というのが安全だと思われます。

--
信岡 ゆう (NOBUOKA Yu)


投稿者 xml-rpc : 2011年9月27日 10:15
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/106573
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。