2011-03-22 63 views
1

我已经得到了的二手一堆使用大量不同的Ruby解释器的人gem,它包括什么归结为以下代码:处理字符串编码与红宝石1.8相同的代码和1.9

res = RestClient.post(...) 
doc = REXML::Document.new(res).root 

res的内容始终是UTF-8,并且在Ruby 1.8中可以正常工作,但如果响应不是纯ASCII ,则用户的默认编码不是UTF-8,但在Ruby 1.9下会出现此错误。现在

,如果我要拍关于Ruby 1.9独自这项工作,我只是坚持res.force_encoding('utf-8')在那里,并用它来完成,但该方法是1.9只,然后红宝石1.8下突破:

NoMethodError: undefined method `force_encoding' for #<String:0x101318178> 

最好的解决方案能想出是这样的,这迫使系统范围的默认编码为UTF-8:

Encoding.default_external = 'UTF-8' if defined? Encoding 

更好的想法,或者这是因为它得到好处呢?对试图使用不同编码的图书馆用户是否会产生负面影响?

+0

为了澄清,我可以依靠传入的内容总是有效的UTF-8。 Ruby 1中的问题。9是String'res'标记了用户的默认编码,该编码可能不是UTF-8,这会导致REXML陷入困境。 – jpatokal 2011-03-29 02:35:26

回答

2

我与迈克刘易斯使用respond_to,但不要在整个代码中的任何位置使用变量res。

我看了看your code in gateway.rb,它看起来像无处不在,你使用的是res时,它会通过向make_api_request呼叫建立,所以你可以在该方法的返回语句前加上这一句:

doc = doc.force_encoding("UTF-8") if doc.respond_to?(:force_encoding) 

即使这是其他地方,但它不是字面上与你遇到的每一个字符串,我相信你可以找到一种方法来重构有意义的代码,并在一个地方,而不是你遇到它的任何地方解决问题。

您是否遇到其他地方的问题?

+0

我没有意识到这一点,但这并不意味着它们不存在......但您的解决方案迄今为止是最好的! – jpatokal 2011-04-01 00:35:59

3
if res.respond_to?(:force_encoding) 
    new_contents = res.force_encoding("UTF-8") 
    else 
    new_contents = res 
    end 

我会做类似的向后兼容性。

+0

但这是一个可怕的kludge,我不想污染我的代码的每一个创建一个像这样的字符串的代码... – jpatokal 2011-03-22 08:54:19

0

如果在使用此方法的特定文件中包含#encoding: utf-8标头,它会起作用吗?

Ruby 1.9在整个应用程序中支持不同的编码,如果这个内容是utf-8编码,应该可以正常工作。

Ruby 1.8会简单地忽略#encoding标题并保持良好运行状态。

这是一个非常简单的方法,但我相信它值得一试!

+0

据我了解,文件头控制源编码,它仅用于用于该源文件中的字符串(例如'str =“Foo”')。它对I/O(例如Restclient)获取的数据没有影响,默认值由外部编码设置。请参阅http://blog.grayproductions.net/articles/ruby_19s_three_default_encodings。 – jpatokal 2011-03-30 01:03:24

1

据我可以从代码片段看到,问题的原因是RestClient,它不会以正确的编码返回字符串(在HTTP响应中指定的那个),所以我首先尝试解决这个问题固定。如果这不能完成,那么你可以用强制编码的代码(迈克刘易斯建议的方式)包装RestClient调用。或者您正在遇到除RestClient调用之外的其他地方的问题?