2012-07-07 111 views
11

我知道有關於這個錯誤的多個類似問題,並且我已經嘗試了很多,但都沒有運氣。我遇到的問題涉及到字節\xA1並拋出字符串#編碼沒有修復「UTF-8中的無效字節序列」錯誤

ArgumentError: invalid byte sequence in UTF-8

我嘗試沒有成功如下:

"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace, 
    :replace => "").sub('', '') 
"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace, 
    :replace => "").force_encoding('UTF-8').sub('', '') 
"\xA1".encode('UTF-8', :undef => :replace, :invalid => :replace, 
    :replace => "").encode('UTF-8').sub('', '') 

每一行引發錯誤我。我究竟做錯了什麼?

UPDATE:

上述線失敗僅在IRB。但是,我修改了我的應用程序以使用相同的String#編碼方法和參數對CVS文件的行進行編碼,並且從文件(請注意:如果您在相同的字符串W/O使用IO)。

bad_line = "col1\tcol2\tbad\xa1" 

bad_line.sub('', '') # does NOT fail 
puts bad_line # => col1 col2 bad? 

tmp = Tempfile.new 'foo' # write the line to a file to emulate real problem 
tmp.puts bad_line 
tmp.close 

tmp2 = Tempfile.new 'bar' 

begin 
    IO.foreach tmp.path do |line| 
    line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "") 
    line.sub('', '') # fail: invalid byte sequence in UTF-8 
    tmp2.puts line 
    end 
    tmp2.close 

    # this would fail if the above error didn't halt execution 
    CSV.foreach(tmp2.path) do |row| 
    puts row.inspect # fail: invalid byte sequence in UTF-8 
    end 
ensure 
    tmp.unlink 
    tmp2.close 
    tmp2.unlink 
end 
+0

這些行都不會在MRI 1.9.3p125的機器上發生錯誤。 – 2012-07-07 13:32:35

+0

我使用MRI 1.9.3p194在IRB中得到這些錯誤。 – joshm1 2012-07-07 13:52:17

回答

30

這似乎是紅寶石認爲,字符串編碼已經是utf8的,所以當你

line.encode!('UTF-8', :undef => :replace, :invalid => :replace, :replace => "") 

它實際上並沒有做任何事情,因爲目標的編碼是一樣的當前編碼(至少這是我對transcode.c中代碼的解釋)

這裏真正的問題是,你的起始數據在某些編碼中是否有效,而不是utf-8,或者這是否是應該是utf-8的數據,但是它有你想丟棄的疣很少。

在第一種情況下,正確的事情是告訴ruby這個編碼是什麼。當你打開文件

File.open('somefile', 'r:iso-8859-1') 

將打開該文件,你可以做到這一點,解釋其內容爲ISO-8859-1

你甚至可以得到紅寶石轉碼爲您

File.open('somefile', 'r:iso-8859-1:utf-8') 

將打開文件爲iso-8859-1,但是當您從中讀取數據時,字節會被轉換爲utf-8。

你也可以調用force_encoding告訴ruby一個字符串的編碼是什麼(這根本不會修改字節,它只是告訴ruby如何解釋它們)。

在第二種情況下,如果您只是想將任何討厭的東西轉儲到您的utf-8中,您不能像調用encode!那樣,因爲這是無效的。在紅寶石2.1和更高版本,可以使用String#scrub,在以前的版本中,你可以做到這一點

line.encode!('UTF-16', :undef => :replace, :invalid => :replace, :replace => "") 
line.encode!('UTF-8') 

我們首先轉換爲UTF-16。由於這是一種不同的編碼,ruby實際上會替換我們的無效序列。然後我們可以轉換回utf-8。這不會讓我們失去任何額外的數據,因爲utf-8和utf-16只是編碼相同底層字符集的兩種不同方式。

+1

謝謝。將它編碼爲UTF-16,然後回到UTF-8做我所需要的。輸入文件的編碼沒有被源定義好,所以我不能使用第一個選項。 – joshm1 2012-07-07 17:53:52

+0

這真是太棒了,非常感謝@Frederick Cheung – JBoy 2015-01-07 13:14:13

+0

@Jboy另請參閱String#scrub如果你正在運行ruby 2.1 – 2015-01-07 13:28:37

2

也許你是在IRB運行這段代碼。 IRB有很多編碼問題。在這種情況下,請嘗試將此代碼保存爲.rb文件並從命令行運行代碼。

+0

是的,你是對的。我在真正的應用程序中發現錯誤後試圖在IRB中解析此問題(使用CVS#解析CVS文件)。在閱讀之前,我會研究將文件編碼爲UTF-8。 – joshm1 2012-07-07 13:56:26

+0

很高興聽到。如果這解決了你的問題,請考慮接受我的答案。 – 2012-07-07 14:41:06

+0

從文件中讀取具有該字節的行(而不僅僅是硬編碼的字符串)時,似乎問題存在於文件中。我用一個更好的例子修改了我原來的帖子。 – joshm1 2012-07-07 15:35:57

相關問題