簡體   English   中英

在Ruby中,如何使用UTF-8編碼這個奇怪的角色?

[英]In Ruby, how to UTF-8 encode this weird character?

我正在從感染了各種奇怪字符的外部數據庫導入內容,例如

> str
=> "Nature’s Variety, Best Friends Animal Society team up"

從上下文看來, 一個€™表示右單引號。 在cp1252編碼中:

> str.encode('cp1252')
=> "Nature\xE2\x80\x99s Variety, Best Friends Animal Society team up"

那么如何將其轉換為正確的UTF-8字符呢? 這是我嘗試過的:

> str.encode('UTF-8')
=> "Nature’s Variety, Best Friends Animal Society team up"

> str.encode('cp1252').encode('UTF-8')
=> "Nature’s Variety, Best Friends Animal Society team up"

> str.encode('UTF-8', invalid: :replace, replace: '?', undef: :replace)
=> "Nature’s Variety, Best Friends Animal Society team up"

> str.encode('cp1252').encode('UTF-8', invalid: :replace, replace: '?', undef: :replace)                                                                  
=> "Nature’s Variety, Best Friends Animal Society team up"

我寧願找到一種方法來進行通用的重新編碼,以便它可以處理所有這些錯誤編碼的字符。 但如果我必須做個人搜索和替換。 但我也無法做到這一點:

> str.encode('cp1252').gsub('\xE2/x80/x99', "'")
=> "Nature\xE2\x80\x99s Variety, Best Friends Animal Society team up"

> str.encode('cp1252').gsub(%r{\xE2\x80\x99}, "'")
SyntaxError: unexpected tIDENTIFIER, expecting $end

> str.encode('cp1252').gsub(Regexp.escape('\xE2\x80\x99'), "'")
=> "Nature\xE2\x80\x99s Variety, Best Friends Animal Society team up"

我想這樣做,但我甚至無法將這些字符粘貼到我的REPL中:

> str.gsub('’', "'")

當我嘗試時,我得到:

> str.gsub('C"b,b,b
* "', ",")
=> "Nature’s Variety, Best Friends Animal Society team up"

令人沮喪。 有關如何將其正確編碼為UTF-8的任何建議?

編輯:在請求字符串中的實際字節時:

> str.bytes.to_a.join(' ')
=> "78 97 116 117 114 101 195 162 226 130 172 226 132 162 115 32 86 97 114 105 101 116 121 44 32 66 101 115 116 32 70 114 105 101 110 100 115 32 65 110 105 109 97 108 32 83 111 99 105 101 116 121 32 116 101 97 109 32 117 112"

修復了從MySQL修復不正確的字符串編碼的問題。 您需要設置正確的編碼然后強制它。

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")
}

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

根據您的數據,可能不需要回退,但它確保它不會通過處理CP1252中未定義的五個字節來引發錯誤。

一旦Ruby編碼錯誤,根據最初的錯誤,字符將保持不正確。 轉換只是將現在錯誤的字符轉換為新的編碼。

要糾正Ruby在輸入上的錯誤,你需要使用force_encoding方法,它不進行轉換,它只是糾正了Ruby對String編碼的注釋。

在您的情況下, 從DB讀取值之前已發生故障。 如果您選擇問題字節: bytes = %w(195 162 226 130 172 226 132 162).map(&:to_i)它們看起來是UTF-8編碼,並且已經在數據庫中進行了雙重編碼。 您可以假設將這些內容寫入數據庫中的任何問題(請注意,如果它是一個實時進程,這是一個需要排序的錯誤,您將繼續獲取這些錯誤的值)。

發生了什么事情是您的DB(或寫入它的代碼)收到了一些代表正確字符的UTF-8字節,但假設它們是CP1252轉換為UTF-8。 它進行了轉換並將有效的UTF-8(但錯誤的字符)寫入數據庫。

如果我在我的終端中使用UTF-8編碼在Ruby控制台中執行以下操作並將其作為默認的Ruby編碼,我可以復制您的問題:

str = "Nature’s Variety, Best Friends Animal Society team up"
 => "Nature’s Variety, Best Friends Animal Society team up"
str = str.force_encoding('CP1252').encode('UTF-8')
 => "Nature’s Variety, Best Friends Animal Society team up"

故障是可逆的,如下所示:

str = str.encode('CP1252').force_encoding('UTF-8')
 => "Nature’s Variety, Best Friends Animal Society team up"

encode('CP1252')撤消了原始的錯誤轉換。

force_encoding('UTF-8')將編碼設置回系統最初可能收到的內容。

您將需要在系統中找到CP1252輸入的假設,而不是UTF-8(如果您在不同的編碼中有多個源,則可能會比這更復雜)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM