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,它只是告诉 Ruby 源文件本身是用 ISO-8859-1 编码的。只需添加

    Encoding.default_external = "iso-8859-1"
    

    如果您希望您读取的所有文件都以该编码存储。

  2. 不,我个人认为 Ruby 不应该自动检测编码,但有理智的人可能不同意这一点,而且“应该这样”的讨论在这里似乎是题外话。

  3. 就个人而言,我对所有内容都使用 UTF-8,并且在我无法控制编码的极少数情况下,我在读取文件时手动设置编码,如上所示。我的源文件总是 UTF-8。如果您正在处理无法控制且不知道其编码的文件,则charguess gem或类似的会很有用。

于 2012-08-04T06:43:21.890 回答