为什么Rails 3认为xE2x80x89意味着x80 x89

时间:2011-07-07 19:47:55

标签: ruby-on-rails unicode utf-8 utf-16 multibyte

我从utf-8页面上删除了一个字段:

"O’Reilly"

并保存在yml文件中:

:name: "O\xE2\x80\x99Reilly"

(xE2x80x99是correct UTF-8 representation of this apostrophe

然而,当我将值加载到哈希并将其输出到标记为utf-8的页面时,我得到:

OâReilly

我查找了字符â,它以UTF-16编码为x00E2,字符x80和x89不可见,但在我粘贴字符串后出现。我认为这意味着我的应用程序输出三个UTF-16字符而不是一个UTF-8。

如何让rails将3字节UTF-8代码解释为单个字符?

3 个答案:

答案 0 :(得分:2)

Ruby字符串是字节序列而不是字符:

$ irb
>> "O\xE2\x80\x99Reilly"
=> "O\342\200\231Reilly"

您的字符串是10个字节但8个字符的序列(如您所知)。看到你在HTML中输出正确的字符串最安全的方法(我假设你想要HTML,因为你提到了Rails)是将不可打印的字符转换为HTML实体;在你的情况下

O’Reilly

这需要一些工作,但在以UTF-8发送HTML但最终用户已将其浏览器设置为覆盖并显示Latin-1或其他一些愚蠢的限制字符集的情况下,它应该会有所帮助。

答案 1 :(得分:2)

最终这是由于使用psych(在rails中)加载syck文件(由外部脚本生成)引起的。使用syck加载解决了这个问题:

#in ruby environment
puts YAML::ENGINE.yamler => syck

#in rails
puts YAML::ENGINE.yamler => psych

#in webapp
YAML::ENGINE.yamler = 'syck'
a = YAML::load(file_saved_with_syck)
a[index][:name] => "O’Reilly"
YAML::ENGINE.yamler = 'psych'

答案 2 :(得分:1)

  

我认为这意味着我的应用程序输出三个UTF-16字符而不是一个UTF-8。

它不是真正的UTF-16,它很少在网上使用(并且很大程度上在那里打破)。您的应用 输出三个Unicode字符(包括两个不可见的控制代码),但这与UTF-16编码不同。

问题似乎是正在读取YAML文件,好像它是ISO-8859-1编码的,因此\xE2字节映射到字符U + 00E2,依此类推。我猜你正在使用Ruby 1.9并且YAML被解析为具有相关ASCII-8BIT编码而不是UTF-8的字节字符串,导致字符串稍后进行一轮转码(修改)。

如果是这种情况,您可能需要force_encoding将读取的字符串恢复到原来的状态,或设置default_internal以使字符串被读回UTF-8。这有点乱。