2012-07-07 32 views
11

Tôi biết có nhiều câu hỏi tương tự về lỗi này và tôi đã thử nhiều người trong số họ mà không gặp may. Vấn đề tôi đang gặp liên quan đến việc byte \xA1 và được némChuỗi # mã hóa không sửa "chuỗi byte không hợp lệ trong UTF-8" lỗi

ArgumentError: invalid byte sequence in UTF-8

Tôi đã thử những điều sau đây không có thành công:

"\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('', '') 

Mỗi dòng ném lỗi cho tôi. Tôi đang làm gì sai?

UPDATE:

Các dòng trên không chỉ trong IRB. Tuy nhiên, tôi đã sửa đổi ứng dụng của mình để mã hóa các dòng của tệp CVS bằng cách sử dụng cùng phương thức và phương thức mã hóa String # và tôi gặp lỗi tương tự khi đọc dòng từ tệp (lưu ý: nó hoạt động nếu bạn thực hiện các thao tác trên cùng một chuỗi w/o bằng cách sử dụng 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

Không có dòng nào trong số này ném lỗi trên máy của tôi với MRI 1.9.3p125. –

+0

Tôi gặp phải các lỗi này trong IRB khi sử dụng MRI 1.9.3p194. – joshm1

Trả lời

30

Dường như ruby ​​nghĩ rằng mã hóa chuỗi đã là utf8, vì vậy khi bạn làm

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

nó không thực sự làm bất cứ điều gì vì bảng mã đích là giống như mã hóa hiện tại (ít nhất đó là cách giải thích của tôi về mã số trong transcode.c)

Câu hỏi thực sự ở đây là liệu dữ liệu bắt đầu của bạn có hợp lệ trong một số mã hóa không phải là utf-8 hoặc liệu đây có phải là dữ liệu được cho là utf-8 hay không vài mụn cóc trong đó mà bạn muốn loại bỏ.

Trong trường hợp đầu tiên, điều chính xác cần làm là cho ruby ​​biết mã hóa này là gì. Bạn có thể làm điều này khi bạn mở file

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

sẽ mở tập tin, giải thích nội dung của nó như iso-8859-1

Bạn thậm chí có thể nhận được ruby ​​để chuyển mã cho bạn

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

sẽ mở tệp dưới dạng iso-8859-1, nhưng khi bạn đọc dữ liệu từ đó, các byte sẽ được chuyển thành utf-8 cho bạn.

Bạn cũng có thể gọi force_encoding để nói cho Ruby biết mã hóa của chuỗi là gì (điều này không thay đổi byte nào cả, nó chỉ cho biết cách giải thích chúng).

Trong trường hợp thứ hai, nơi bạn chỉ muốn bỏ bất kỳ nội dung khó chịu nào vào trong utf-8 của mình, bạn không thể chỉ gọi số encode! như bạn có vì đó là số không. Trong ruby ​​2.1 trở lên, bạn có thể sử dụng String#scrub, trong các phiên bản trước, bạn có thể làm điều này

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

Chúng tôi đầu tiên chuyển đổi sang utf-16. Vì đây là một mã hóa khác, ruby ​​sẽ thực sự thay thế các chuỗi không hợp lệ của chúng ta. Sau đó chúng tôi có thể chuyển đổi thành utf-8.Điều này sẽ không làm mất bất kỳ dữ liệu bổ sung nào vì utf-8 và utf-16 chỉ là hai cách mã hóa khác nhau cùng một bộ ký tự cơ bản.

+1

Cảm ơn. Mã hóa nó thành UTF-16 sau đó quay trở lại UTF-8 đã làm những gì tôi cần. Mã hóa của tệp đầu vào không được xác định rõ bởi nguồn, vì vậy tôi không thể sử dụng tùy chọn đầu tiên. – joshm1

+0

Điều này thật tuyệt vời, cảm ơn bạn rất nhiều @Frederick Cheung – JBoy

+0

@Jboy cũng xem chuỗi # chà nếu bạn đang chạy ruby ​​2.1 –

2

Có thể bạn đang chạy mã này trong IRB. Tôi đã có rất nhiều vấn đề mã hóa với IRB. Trong trường hợp này, hãy thử lưu mã này dưới dạng tệp .rb và chạy mã từ dòng lệnh.

+0

Vâng, bạn nói đúng. Tôi đã cố gắng để giải quyết điều này trong IRB sau khi tôi tìm thấy trong lỗi trong một ứng dụng thực tế (phân tích một tập tin CVS với CVS # đọc). Tôi sẽ xem xét mã hóa tệp thành UTF-8 trước khi đọc nó. – joshm1

+0

Rất vui khi được nghe. Nếu điều đó giải quyết được vấn đề của bạn, hãy xem xét chấp nhận câu trả lời của tôi. –

+0

Dường như vấn đề tồn tại trong các tệp khi một dòng với byte đó được đọc từ một tệp (và không chỉ là một chuỗi được mã hóa cứng). Tôi đã sửa đổi bài đăng gốc của mình bằng một ví dụ tốt hơn. – joshm1

Các vấn đề liên quan