Ruby 为什么HAML在ERB和ERUBIS没有的情况下抛出编码问题

Ruby 为什么HAML在ERB和ERUBIS没有的情况下抛出编码问题,ruby,encoding,haml,padrino,Ruby,Encoding,Haml,Padrino,请按照以下代码操作: __ENCODING__ # => #<Encoding:UTF-8> Encoding.default_internal # => #<Encoding:UTF-8> Encoding.default_external # => #<Encoding:UTF-8> 案例2:HAML不会抛出错误 string = "Ratatouille".force_encoding('ASCII-8BIT') stri

请按照以下代码操作:

__ENCODING__
# => #<Encoding:UTF-8>

Encoding.default_internal
# => #<Encoding:UTF-8> 

Encoding.default_external
# =>  #<Encoding:UTF-8> 
案例2:HAML不会抛出错误

string = "Ratatouille".force_encoding('ASCII-8BIT')

string.encoding
# => #<Encoding:ASCII-8BIT>

Haml::Engine.new("#{string}").render
## => "Ratatouille\n"
## => resulting encoding is #<Encoding:UTF-8>    

ERB.new("<%= string %>").result(binding)
# => "Ratatouille"
# => resulting encoding is #<Encoding:UTF-8> 

Erubis::Eruby.new("<%= string %>").result(binding)
# => "Ratatouille" 
# => result encoding is #<Encoding:US-ASCII> 
string=“Ratatouille”。强制编码(“ASCII-8BIT”)
字符串编码
# => #
Haml::Engine.new(“#{string}”).render
##=>“杂烩菜\n”
##=>结果编码为#
ERB.新(“”)结果(有约束力)
#=>“杂烩”
#=>结果编码为#
Erubis::Eruby.new(“”)结果(绑定)
#=>“杂烩”
#=>结果编码为#
问题: 为什么HAML在案例1中失败而在案例2中成功

为什么我要问,当HAML中的渲染由于编码::CompatibilityError炸毁页面时,我会面临类似的问题

string = "Ratatouille".force_encoding('ASCII-8BIT')

string.encoding
# => #<Encoding:ASCII-8BIT>

Haml::Engine.new("#{string}").render
## => "Ratatouille\n"
## => resulting encoding is #<Encoding:UTF-8>    

ERB.new("<%= string %>").result(binding)
# => "Ratatouille"
# => resulting encoding is #<Encoding:UTF-8> 

Erubis::Eruby.new("<%= string %>").result(binding)
# => "Ratatouille" 
# => result encoding is #<Encoding:US-ASCII> 
目前我认为我知道如何避免错误的唯一方法是使用
将我的字符串强制编码为UTF8。强制编码('UTF-8')
哪种方式可以避免这个问题,但我必须在我想要使用给定字符串的每一页中都这样做,即“j\xC3\xBCrgen”(考虑到他们的页面太多,我觉得这样做有点蹩脚)

书中有什么线索吗

Ruby支持一种称为ASCII-8BIT的虚拟编码。尽管名称中有ASCII码,但这是 真正打算用于包含二进制数据的数据流(这就是为什么它有 二进制}的别名。但是,您也可以将其用作源文件的编码。如果你这样做, Ruby将代码低于128的所有字符解释为常规ASCII和所有其他字符 作为变量名的有效成分。这基本上是一个整洁的黑客,因为它允许您 要编译以编码方式编写的文件,您不知道高阶字符 将假定位集是可打印的

String#force_编码
告诉Ruby使用哪种编码来解释一些二进制数据。它不更改/转换实际字节(即
String#encode
),只更改与这些字节关联的编码

为什么要尝试将二进制编码与包含UTF-8字符的字符串相关联


关于第二个案例成功的原因,答案很简单,第二个字符串(“Ratatouille”)仅包含7位ASCII字符。

Haml正在尝试将结果字符串编码到您的设置中。在第一个示例中,字符串(
“j\xC3\xBCrgen”
)包含非ASCII字节(即设置高位的字节),而第二个示例中的字符串(
“Ratatouille”
)不包含。Ruby可以对第二个字符串进行编码(因为UTF-8是ASCII的超集),但不能对第一个字符串进行编码,并引发错误

解决这个问题的一种方法是显式地将字符串编码作为选项传递给
Haml::encoding

Haml::Engine.new("#{string}", :encoding => Encoding::ASCII_8BIT).render
这将为您提供一个同样为ASCII-8BIT的结果字符串

在本例中,所讨论的字符串是UTF-8,因此更好的解决方案可能是查看该字符串在应用程序中的来源,并确保其具有正确的编码


我对ERB和Erubis的了解还不足以说明发生了什么,看起来ERB错误地假设它是UTF-8(它现在有办法知道这些字节实际上应该被视为UTF-8),而Erubis正在做更明智的事情,将编码保留为二进制——或者因为它根本没有做任何编码,或者它专门处理二进制编码的输入。

如果将字符串直接传递到
引擎.new()
调用而不插入它,会发生什么情况?可能会有人认为,在这里引发错误是Haml中的一个错误。我不确定
default\u internal
的其他用户如何处理这个问题,最好保持二进制文件不变。是的,我甚至觉得在HAML中引发错误有点迟钝,因为默认的内部编码是
UTF-8
,我假设“j\xC3\xBCrgen”是有效的UTF-8字符串,所以要消除错误,请始终使用
force_编码('UTF-8')
是我应该从上述答案中得出的结论correct@Ratatouille“j\xC3\xBCrgen”是一个有效的UTF-8字符串,但无法仅从该字符串知道它是否应该是UTF-8。通常应避免使用
force_编码
——解决这一问题的最佳方法是确保在从外部源读取字符串时对其进行正确编码。如果由于某种原因不能这样做,并且您知道字符串是有效的UTF-8,您可以求助于
force_encoding
。非常抱歉,您的回复有点晚,接受了答案