2012-05-05 81 views
7

「的UTF-8無效字節序列」在IRB,我想以下幾點:紅寶石String.encode仍然給

1.9.3p194 :001 > foo = "\xBF".encode("utf-8", :invalid => :replace, :undef => :replace) 
=> "\xBF" 
1.9.3p194 :002 > foo.match /foo/ 
ArgumentError: invalid byte sequence in UTF-8 
from (irb):2:in `match' 

任何想法是怎麼回事?

回答

21

我猜"\xBF"已經認爲它是UTF-8編碼,所以當你打電話encode,它認爲你試圖在編碼UTF-8 UTF-8字符串和無助:

>> s = "\xBF" 
=> "\xBF" 
>> s.encoding 
=> #<Encoding:UTF-8> 

\xBF不是有效的UTF-8,所以這當然是無稽之談。但是如果你使用的encode三個參數的形式:

編碼(dst_encoding,src_encoding [,選項])→STR

[...]第二種形式返回從轉碼的str副本src_encodingdst_encoding

您可以強制問題告訴encode忽略該字符串認爲它的編碼是,把它作爲二進制數據:

>> foo = s.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace) 
=> "�" 

哪裏s是,認爲這是UTF-8從"\xBF"以上。

你也使用force_encodings,迫使它是二進制文件,然後用兩個參數encode

>> s.encoding 
=> #<Encoding:UTF-8> 
>> s.force_encoding('binary') 
=> "\xBF" 
>> s.encoding 
=> #<Encoding:ASCII-8BIT> 
>> foo = s.encode('utf-8', :invalid => :replace, :undef => :replace) 
=> "�" 
+0

謝謝你的選擇!使用'ascii'作爲編碼也起作用。 – drewinglis

+1

@drewinglis:我喜歡「binary」的明確性(這是「ascii-8bit」的別名),「ascii」並不完全相同。 –

2

如果你看過在使用顯式代碼頁的源文本文件這是固定的:

File.open('thefile.txt', 'r:iso8859-1') 
2

如果你只使用ASCII字符,則可以使用

>> "Hello \xBF World!".encode('utf-8', 'binary', :invalid => :replace, :undef => :replace) 
=> "Hello � World!" 

但是如果我們用同樣的方法與有效的UTF8字符是ASCII

>> "¡Hace \xBF mucho frío!".encode('utf-8', 'binary', :invalid => :replace, :undef => :replace) 
=> "��Hace � mucho fr��o!" 

嗯哦無效會發生什麼!我們希望frío保持口音。下面是保持有效的UTF8字符

>> "¡Hace \xBF mucho frío!".chars.select{|i| i.valid_encoding?}.join 
=> "¡Hace mucho frío!" 

而且在Ruby中2.1有一個叫scrub新的方法來解決這個問題

>> "¡Hace \xBF mucho frío!".scrub 
=> "¡Hace � mucho frío!" 
>> "¡Hace \xBF mucho frío!".scrub('') 
=> "¡Hace mucho frío!"