3

次の内容の ruby​​ ファイルがあります。

# encoding: iso-8859-1
File.open('foo.txt', "w:iso-8859-1") {|f| f << 'fòo'}
puts File.read('foo.txt').encoding
  • Windowsコマンドプロンプトruby 1.9.3から実行すると、次のようになります:IBM437
  • cygwin ruby​​ 1.9.3 から実行すると、次のようになります: UTF-8
  • 私が期待するものは次のとおりです: iso-8859-1

誰かがここで何が起こっているのか説明できますか?

アップデート

これが私が探しているもののより良い説明です:

  • Darshan のおかげで、Ruby はデフォルトで Encoding.default _external にファイルをロードすることを理解しましたが、 # encoding: iso-8859-1 行はそれを上書きすべきではありませんか?
  • ruby はファイルのエンコーディングを自動検出できるべきですか? エンコーディングが属性であるファイルシステムはありますか?
  • ファイルを保存したエンコーディングを「記憶」するための最良のオプションは何ですか?
4

1 に答える 1

7

ファイルを読み取るときにエンコーディングを指定していません。そこを除いてどこでも指定するように細心の注意を払っていますが、デフォルトのエンコーディングで読んでいます。

File.open('foo.txt', "w:iso-8859-1") {|f| f << 'fòo'.force_encoding('iso-8859-1')}
File.open('foo.txt', "r:iso-8859-1") {|f| puts f.read().encoding }

# => ISO-8859-1

'fòo'.encode('iso-8859-1')また、おそらくではなくを意味することに注意してください'fòo'.force_encoding('iso-8859-1')。後者はバイトを変更せずに残しますが、前者は文字列をトランスコードします。

更新:私はできる限り明確または完全ではなかったので、少し詳しく説明します。

  1. でエンコーディングを指定しない場合File.read()、ファイルは で読み込まれEncoding.default_externalます。自分で設定していないため、Ruby は実行環境に応じて値を使用しています。Windows 環境では、IBM437 です。Cygwin 環境では、UTF-8 です。したがって、上記の私のポイントは、もちろんそれがエンコーディングであるということでした。ファイルに含まれるバイト数とは関係ありません。Ruby はエンコーディングを自動検出しません。

  2. force_encoding()文字列のバイトは変更されず、それらのバイトに添付されたエンコーディングのみが変更されます。Ruby に「この文字列を ISO-8859-1 のふりをして」と伝えると、「この文字列を ISO-8859-1 と書いてください」と伝えてもトランスコードされません。 encode()ファイルへの書き込みと同様に、だまされないようにします。

ISO-8859-1 のソース ファイルがある場合、これらをまとめると、次のようになります。

# encoding: iso-8859-1

# Write in ISO-8859-1 regardless of default_external
File.open('foo.txt', "w:iso-8859-1") {|f| f << 'fòo'}

# Read in ISO-8859-1 regardless of default_external,
#  transcoding if necessary to default_internal, if set
File.open('foo.txt', "r:iso-8859-1") {|f| puts f.read().encoding } # => ISO-8859-1

puts File.read('foo.txt').encoding # -> Whatever is specified by default_external

ソース ファイルが UTF-8 の場合:

# encoding: utf-8

# Write in ISO-8859-1 regardless of default_external, transcoding from UTF-8
File.open('foo.txt', "w:iso-8859-1") {|f| f << 'fòo'}

# Read in ISO-8859-1 regardless of default_external,
#  transcoding if necessary to default_internal, if set
File.open('foo.txt', "r:iso-8859-1") {|f| puts f.read().encoding } # => ISO-8859-1

puts File.read('foo.txt').encoding # -> Whatever is specified by default_external

新しい質問に答える更新 2:

  1. いいえ、# encoding: iso-8859-1行は変わりませんEncoding.default_external。ソース ファイル自体が ISO-8859-1 でエンコードされていることを Ruby に伝えるだけです。追加するだけ

    Encoding.default_external = "iso-8859-1"
    

    読み取ったすべてのファイルがそのエンコーディングで保存されると予想される場合。

  2. いいえ、個人的には Ruby がエンコーディングを自動検出するべきだとは思いませんが、合理的な人々はそれについて異議を唱えることができます。

  3. 個人的には、すべてに UTF-8 を使用しており、エンコーディングを制御できないまれな状況では、上記のように、ファイルを読み取るときに手動でエンコーディングを設定しています。ソース ファイルは常に UTF-8 です。制御できず、エンコーディングがわからないファイルを扱っている場合は、charguess gemなどが役立ちます。

于 2012-08-04T06:43:21.890 に答える