windows上的ruby 1.9错误的文件编码

pgu*_*rio 3 ruby windows encoding

我有一个包含以下内容的ruby文件:

# encoding: iso-8859-1
File.open('foo.txt', "w:iso-8859-1") {|f| f << 'fòo'}
puts File.read('foo.txt').encoding
Run Code Online (Sandbox Code Playgroud)
  • 当我从Windows命令提示符ruby 1.9.3运行它时,我得到:IBM437
  • 当我从cygwin ruby​​ 1.9.3运行它时,我得到:UTF-8
  • 我期望得到的是:iso-8859-1

有人能解释一下这里发生了什么吗?

UPDATE

这里有一个更好的描述我正在寻找:

  • 我理解现在感谢Darshan,默认情况下ruby会在Encoding.default _external中加载文件,但#encoding:iso-8859-1行不应该覆盖吗?
  • ruby能否自动检测文件的编码?是否存在编码属性的文件系统?
  • 什么是"记住"我保存文件的编码的最佳选择?

Dar*_*tle 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
Run Code Online (Sandbox Code Playgroud)

还要注意你可能意味着'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
Run Code Online (Sandbox Code Playgroud)

如果您有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
Run Code Online (Sandbox Code Playgroud)

更新2,回答您的新问题:

  1. 不,该# encoding: iso-8859-1行不会改变Encoding.default_external,它只告诉Ruby源文件本身是用ISO-8859-1编码的.只需添加

    Encoding.default_external = "iso-8859-1"
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 不,我个人认为Ruby不应该自动检测编码,但合理的人可能会对此不一致,而且"应该如此"的讨论在这里似乎是偏离主题的.

  3. 就个人而言,我使用UTF-8作为一切,在极少数情况下我无法控制编码,我在阅读文件时手动设置编码,如上所示.我的源文件始终是UTF-8.如果你正在处理你无法控制但不知道编码的文件,那么charguess gem或类似物就会很有用.