将非ASCII字符从ASCII-8BIT转换为UTF-8

时间:2011-02-01 21:01:23

标签: ruby utf-8 internationalization

我正在从远程站点提取文本并尝试将其加载到默认使用utf-8的Ruby 1.9 / Rails 3应用程序中。

以下是一些违规文字的示例:

Cancer Res; 71(3); 1-11. ©2011 AACR.\n

扩展的版权代码如下所示:

Cancer Res; 71(3); 1-11. \xC2\xA92011 AACR.\n

Ruby告诉我字符串被编码为ASCII-8BIT并且输入我的Rails应用程序让我这样:

incompatible character encodings: ASCII-8BIT and UTF-8

我可以使用此正则表达式删除版权代码

str.gsub(/[\x00-\x7F]/n,'?')

生成这个

Cancer Res; 71(3); 1-11. ??2011 AACR.\n

但是如何在UTF-8中将版权符号(以及其他各种符号,如希腊字母)转换转换为相同的符号?当然有可能......

我看到使用force_encoding的引用,但这不起作用:

str.force_encoding('utf-8').encode

我意识到还有很多其他人有类似的问题,但我还没有看到一个有效的解决方案。

4 个答案:

答案 0 :(得分:61)

这对我有用:

#encoding: ASCII-8BIT
str = "\xC2\xA92011 AACR"
p str, str.encoding
#=> "\xC2\xA92011 AACR"
#=> #<Encoding:ASCII-8BIT>

str.force_encoding('UTF-8')
p str, str.encoding
#=> "©2011 AACR"
#=> #<Encoding:UTF-8>

答案 1 :(得分:27)

有两种可能性:

  1. 输入数据已经是UTF-8,但Ruby只是不知道它。这似乎是你的情况,因为“\ xC2 \ xA9”是版权符号的有效UTF-8。在这种情况下,您只需要使用force_encoding告诉Ruby数据已经是UTF-8。

    例如“\ xC2 \ xA9”.force_encoding('ASCII-8BIT')会重新创建输入数据的相关位。而“\ xC2 \ xA9”.force_encoding('ASCII-8BIT')。force_encoding('UTF-8')将证明你可以告诉Ruby它真的是UTF-8并获得所需的结果。

    < / LI>
  2. 输入数据采用其他编码方式,您需要Ruby将其转码为UTF-8。在这种情况下,你必须告诉Ruby当前的编码是什么(ASCII-8BIT对于二进制来说是ruby-speak,它不是真正的编码),然后告诉Ruby对其进行转码。

    例如,假设您的输入数据是ISO-8859-1。在该编码中,版权符号仅为“\ xA9”。这将生成如此一些数据:“\ xA9”.force_encoding('ISO-8859-1')这将证明您可以让Ruby将其转码为UTF-8:“\ xA9”.force_encoding('ISO -8859-1 ')。编码(' UTF-8' )

答案 2 :(得分:6)

我曾经使用open-uri,iconv和Hpricot来抓取希腊Windows编码页面的脚本:

doc = open(DATA_URL)
doc.rewind
data = Hpricot(Iconv.conv('utf-8', "WINDOWS-1253", doc.readlines.join("\n")))

我认为这是Ruby 1.8.7,不确定ruby 1.9的内容是什么

答案 3 :(得分:1)

我在字符编码方面一直遇到问题,其他答案也很有帮助,但并非在每种情况下都有效。这是我想出的解决方案,它在可能的情况下强制编码,而在不可能的情况下使用'?'进行代码转换。解决方法如下:

  def encode str
    encoded = str.force_encoding('UTF-8')
    unless encoded.valid_encoding?
      encoded = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
    end
    encoded
  end

force_encoding在大多数情况下都有效,但是我遇到了一些失败的字符串。这样的字符串将替换无效的字符:

 str = "don't panic: \xD3"
 str.valid_encoding?
 false
 str = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
 "don't panic: ?"
 str.valid_encoding?
 true

更新:以上代码在生产中遇到了一些问题。我建议您使用已知的问题文本设置单元测试,以确保该代码可以按您的需要为您工作。一旦提出了版本2,我将更新此答案。