2014-09-11 78 views
1

背景

我已經有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表達式,但我寧願避免這種情況。

回答

1

我想我可以寫一個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