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

问题描述:

背景

我已经有Postgres数据库中的数据在某个点被错误地编码。修复Ruby中错误编码的字符串

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字符?

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

我想我可以写一个ginormous 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