【发布时间】:2023-03-30 22:20:01
【问题描述】:
背景
我的 Postgres 数据库中的数据在某些时候被错误地编码。
数据库采用 UTF-8 编码。有问题的表有一列包含 YAML 序列化数据。某些行包含似乎由它们的两字节 UTF 等效项表示的非 ascii 字符。更容易展示:
> 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 表达式,但我宁愿避免这样做。
【问题讨论】: