修复MySQL不正确的字符串编码
我正在从一个没有为Unicode设置的mysql数据库中读取字符串。
Ruby将字符串作为七大洋
但我知道正确的版本应该是七大洋
。 “错误”字符串被编码为UTF-8,因为Ruby不知道它有错误。 我已经尝试在受损的字符串上强制执行每个编码,但没有任何作用。 我有一种感觉,我可以通过摆弄这些位来做到这一点,但我甚至不知道从哪里开始。
我认为没有任何信息丢失,因为错误的字符串实际上比正确的字符串有更多的字节。 我不认为Ruby是这里的罪魁祸首,因为当我在Ruby之外查看表时,字符串看起来也很糟糕 – 所以我希望能够消除MySQL已经造成的损害。
您可以使用以下构造来还原编码:
"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]
因此,要将您的字符串转换为七大洋
您可以使用上面的任何编码。
亚历山大指出了我的主要错误(你需要encode
然后使用force_encoding
来找到正确的编码)。 该字符串确实编码为CP1252!
最好的解决方案是从MySQL读取二进制文件然后强制编码:
client = Mysql2::Client.new(opts.merge encoding: 'binary') # ... text.force_encoding('UTF-8')
或者,如果您无法更改获取数据的方式,则在尝试encode
时将遇到Encoding::UndefinedConversionError
。 正如本博文中所详述的 ,解决方案是为五个未定义的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')