修复MySQL不正确的字符串编码

时间:2014-10-27 21:02:33

标签: mysql ruby unicode character-encoding

我正在从没有为Unicode设置的mysql数据库中读取字符串。

Ruby将字符串作为七大洋获取,但我知道正确的版本应为七大洋。 “错误”字符串被编码为UTF-8,因为Ruby不知道它有错。我已经尝试在受损的字符串上强制每个编码,但没有任何作用。我有一种感觉,我可以通过摆弄这些位来做到这一点,但我甚至不知道从哪里开始。

我认为没有任何信息丢失,因为错误的字符串实际上比正确的字符串更多字节。我不认为Ruby是罪魁祸首,因为当我在Ruby之外查看表时,字符串看起来也很糟糕 - 所以我希望能够消除MySQL已经造成的损害。

2 个答案:

答案 0 :(得分:3)

您可以使用以下构造来恢复编码:

"wrong_string".encode(Encoding::SOME_ENCODING).force_encoding('utf-8')

我尝试了所有可能的编码来检测正确的编码:

Encoding.constants.each_with_object({}) do |encoding_name, result|
  value = "七大洋".encode(Encoding.const_get encoding_name).force_encoding('utf-8') rescue nil
  result[encoding_name] = value if value == "七大洋"
end.keys
#=> [:Windows_1252, :WINDOWS_1252, :CP1252, :Windows_1254, :WINDOWS_1254, :CP1254]

因此,要将字符串转换为七大洋,您可以使用上面的任何编码。

答案 1 :(得分:2)

亚历山大指出了我的主要错误(您需要encode然后force_encoding才能找到正确的编码。该字符串确实编码为CP1252!

最好的解决方案是从MySQL读取二进制文件然后强制编码:

client = Mysql2::Client.new(opts.merge encoding: 'binary')
# ...
text.force_encoding('UTF-8')

或者,如果您无法更改获取数据的方式,那么当您尝试Encoding::UndefinedConversionError时,您将会遇到encode。如this blog post中所述,解决方案是指定five undefined CP1252字节的编码:

fallback = {
  "\u0081" => "\x81".force_encoding("CP1252"),
  "\u008D" => "\x8D".force_encoding("CP1252"),
  "\u008F" => "\x8F".force_encoding("CP1252"),
  "\u0090" => "\x90".force_encoding("CP1252"),
  "\u009D" => "\x9D".force_encoding("CP1252")
}

text.encode('CP1252', fallback: fallback).force_encoding('UTF-8')