[ruby-list:45777] Re: Ruby 1.9.1-rc1[mswin32]でマルチバイトを含むソースが実行できない

From: rubikitch@...
Date: 2009-01-01 09:33:08 UTC
List: ruby-list #45777
From: "Ayumu Aizawa" <ayumu.aizawa@gmail.com>
Subject: [ruby-list:45773] Re: Ruby 1.9.1-rc1[mswin32]でマルチバイトを含むソースが実行できない
Date: Thu, 1 Jan 2009 17:43:20 +0900

> そして-Eex[:in]というオプションが追加されているみたいなのですが、これの使い方が
> よくわからないです。
>
>   -Eex[:in]       specify the default external and internal character encodings
>  →規定の外部/内部エンコーディングを指定する

これはdefault_externalとdefault_internalを設定します。
IOエンコーディングの設定なのでスクリプトエンコーディングを変更するわけではありません。

> ということみたいなのですが、先ほどの例に-Esjis:sjis を指定してもやはりASCIIと解釈
> されている(?)みたいです。
> 
> C:\tmp>type test_sjis.rb
> str = "あいうえお"
> puts str
> 
> C:\tmp>ruby -v -Esjis:sjis test_sjis.rb
> ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32]
> test_sjis.rb:1: invalid multibyte char (US-ASCII)
> test_sjis.rb:1: invalid multibyte char (US-ASCII)

Ruby 1.9を使い始めた人にははまりやすい点ですが、IOのエンコーディングと
スクリプトエンコーディングは「別々」です。
スクリプトエンコーディングはmagic commentで設定します。
個々のスクリプトがエンコーディングを持つことで、別々の文字コードで書かれた
スクリプトをシームレスに読み込むことができます。

-Ksな状況においてEUC-JPで書かれたスクリプトを読み込ませようと思ったら、
Ruby 1.8までだと$KCODEを設定しなおさないといけません。

require 'sjis'
$KCODE='e'
require 'euc'
$KCODE='s'
〜

↓ Ruby 1.9だとエンコーディングが導入されたおかげで

require 'sjis'
require 'euc'
〜


さて、default_externalについてですが、これは外界(ファイル)の
デフォルトのエンコーディングです。これはロケールによって決まってきます。
たとえばWindows環境だとWindows-31J(Shift_JISの亜種/Windowsで使われている)
となっているでしょう。
そのため、ファイルを読み込んだときのエンコーディングはWindows-31Jが
前提となります。

しかし、他のエンコーディングのファイルを読み込んでしまうと、
今度はRubyがエンコーディングを誤認してしまいます。
そのときはIOのエンコーディングを明示的に設定してあげる必要があります。

# Rubyが暗黙的にファイルのエンコーディングを推測するわけではありません。

# 以下は、EUC-JPをdefault_externalとします。

普段は通常通り書いてよいです。

$ ruby19 -rkconv -e 'f = File.read("euc.txt"); p [f.encoding, Kconv.guess(f)]'
[#<Encoding:EUC-JP>, #<Encoding:EUC-JP>]

EUC-JPの環境でUTF-8のファイルを読み込ませると、Rubyのエンコーディングが
誤認してしまいます。

$ ruby19 -rkconv -e 'f = File.read("utf8.txt"); p [f.encoding, Kconv.guess(f)]'
[#<Encoding:EUC-JP>, #<Encoding:UTF-8>]

そこでdefault_externalをUTF-8に設定しておくと、エンコーディングの不一致が
起こらなくなります。

$ ruby19 -rkconv -E UTF-8 -e 'f = File.read("utf8.txt"); p [f.encoding, Kconv.guess(f)]'
[#<Encoding:UTF-8>, #<Encoding:UTF-8>]

ただ、default_externalはグローバルな状態なので影響範囲が大きいです。
局所的に別のエンコーディングのファイルを読み込む際には、そのIOのエンコーディングを
設定したほうがよいでしょう。

$ ruby19 -rkconv -e 'f = open("utf8.txt", "r:UTF-8").read; p [f.encoding, Kconv.guess(f)]'
[#<Encoding:UTF-8>, #<Encoding:UTF-8>]

default_internalはファイル読み込み時に暗黙的にエンコーディングを変換します。
危険なのでおすすめできません。

$ ruby19 -rkconv -E EUC-JP:UTF-8 -e 'f = File.read("euc.txt"); p [f.encoding, Kconv.guess(f)]'
[#<Encoding:UTF-8>, #<Encoding:UTF-8>]


--
rubikitch
Blog: http://d.hatena.ne.jp/rubikitch/
Site: http://www.rubyist.net/~rubikitch/

In This Thread