2014-10-27 105 views
1

我正在從未設置爲Unicode的mysql數據庫讀取字符串。修復從MySQL不正確的字符串編碼

Ruby得到的字符串爲七大洋但我知道正確的版本應該是七大洋。 「錯誤的」字符串編碼爲UTF-8,因爲Ruby不知道它有錯。我試圖強制每個編碼的mangled字符串,但沒有任何工作。我有一種感覺,我可以通過擺弄這些東西來做到這一點,但我甚至不知道從哪裏開始。

我不認爲有任何信息丟失,因爲不正確的字符串實際上有更多字節比正確的字節。我不認爲Ruby是這裏的罪魁禍首,因爲當我在Ruby之外查看錶時,字符串看起來會變得很糟糕 - 所以我希望能夠消除MySQL已經完成的破壞。

回答

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] 

因此,爲了您的字符串轉換爲七大洋你可以使用任何編碼從上面。

+0

使用'Encoding.list'或'Encoding.name_list'代替'Encoding.constants'。 – Stefan 2014-10-27 21:58:38

2

Alexander指出我的主要錯誤(你需要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')