修复Ruby中错误编码的字符串

时间:2014-09-11 08:33:03

标签: ruby character-encoding

背景

我在Postgres数据库中获得的数据在某些时候编码错误。

DB是UTF-8编码的。有问题的表有一列包含YAML序列化数据。某些行包含非ascii字符,这些字符似乎由它们的双字节UTF等价物表示。它更容易展示:

> puts data
#  ---
#  :method_name: new
#  :method_args:
#  - "M\xC3\xB6bler"
#  - ""
#  - false
#  - ""
#  - test
#  - f8685480-a36b-012f-54c1-1093e95ec0bb

> data.encoding
# => # <Encoding:UTF-8>

\xC3\xB6应该是字符ö

使用unicode字符串执行此操作可以获得相同类型的结果:

> string = "ö".force_encoding("ascii-8bit")
# => "\xC3\xB6"

但是,在这种情况下,保留原始字节,以便我们可以转换回UTF:

> string.force_encoding("utf-8")
# => "ö"

打印\xC3\xB6似乎只是一种显示ASCII-8BIT中没有意义的字节的方法。您可以通过致电.chars

来说明这一点
> string.chars
# => ["\xC3", "\xB6"]

但是在来自数据库的字符串中,\xC3\xB6实际上是八个字符。

> data[42..49].chars
# => ["\\", "x", "C", "3", "\\", "x", "B", "6"]

正因为如此,你不能强迫使用ASCII-8bit再返回 - 这是我第一次尝试解决方案。

我的下一个想法是以某种方式恢复原始字节,但这比我想象的更难。

这里建议了一个可能的(hackish)解决方案:Best way to escape and unescape strings in Ruby?

该解决方案对我不起作用,可能是因为该字符串代表YAML。

问题

如何恢复原始的unicode字符?

我想我可以编写一个巨大的gsub表达式,但我宁愿避免这种情况。

1 个答案:

答案 0 :(得分:1)

  

我想我可以编写一个巨大的gsub表达式,但我宁愿避免这种情况。

不是那么大胆:)

string = "M\\xC3\\xB6bler"
string.encoding
# => #<Encoding:UTF-8>

puts string.gsub(/\\x([0-9a-zA-Z]{2})/) { $1.to_i(16).chr }
# => Möbler