【问题标题】:ruby 1.9 wrong file encoding on windowsWindows上的ruby 1.9错误的文件编码
【发布时间】:2012-08-04 06:39:12
【问题描述】:

我有一个包含以下内容的 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 应该能够自动检测文件的编码吗?有没有 编码是属性的文件系统?
  • “记住”我保存文件的编码的最佳选择是什么 在?

【问题讨论】:

    标签: ruby windows encoding


    【解决方案1】:

    您在读取文件时没有指定编码。您非常小心地在除那里之外的任何地方指定它,但是您正在使用默认编码读取它。

    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 或类似名称会很有用。

    【讨论】:

    • 我试图证明我正在将 iso-8859-1 字符串写入文件,但是当我读取文件内容时,编码是错误的。假设我不只是编写那个文件,而且我不知道它的编码。
    • @pguardiario 好的,在解释发生的事情时,我没有尽我所能。我刚刚对我的回答进行了重大更新。
    • 我想我自己也不清楚。 - 我使用 force_encoding 来消除字符串可能不是这种编码的任何疑问。我现在意识到我可能引入了额外的混乱。 - 我发现参考资料表明 ruby​​ 实际上应该自动检测文件的编码,所以我正在寻找一种确定的方式。
    • @pguardiario 同样,force_encoding(enc) 仅确保 Ruby 会假装编码为 enc;如果还没有,它不会将其 转码为 enc。有用于编码检测的 gem,但 Ruby 本身不这样做,读取文件使用Encoding.default_external,除非您指定编码。
    • 是的,关于 Encoding.default _external 的评论很有见地,但让我们忘记 force_encoding,它与问题无关。我将更新对我正在寻找的内容的更好描述。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多