2012-07-05 82 views
43

Đây là những nỗ lực của tôi với thông báo lỗi. Tôi đang làm gì sai?mã hóa và giải mã chuỗi?

string.decode("ascii", "ignore") 

UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 37: ordinal not in range(128)

string.encode('utf-8', "ignore") 

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 37: ordinal not in range(128)

+0

Giá trị của 'chuỗi' là gì? Loại đó là gì? –

+0

Nó không có ý nghĩa để giải mã một đối tượng Unicode vì nó đã ở dạng giải mã. Khi bạn gọi unicode_object.decode(), Python giả sử bạn muốn giải mã một chuỗi byte thành Unicode thay thế. Đầu tiên nó cố gắng mã hóa đối tượng Unicode dưới dạng chuỗi byte bằng cách sử dụng mã hóa mặc định của hệ thống - đó là lỗi thực sự bạn đang thấy. – kumar303

Trả lời

74

Bạn không thể giải mã một unicode, và bạn không thể mã hóa một str. Hãy thử làm điều đó the other way around.

+6

Chính xác nhưng có thể một chút điện báo vì vậy tôi đã thêm một lời giải thích chi tiết hơn. – Duncan

+1

Từ khôn ngoan ... Tôi ước gì tôi đã đọc trước đó – Remiz

+6

Tôi có phải là người duy nhất nghĩ rằng Python có cách này sai không? Khi tôi biến một chuỗi python thành biểu diễn nhị phân utf-8 của nó, chắc chắn rằng nên được gọi là "mã hóa", và không phải là cách khác xung quanh? –

2

Đó là vì chuỗi đầu vào của bạn không thể được chuyển đổi theo các quy tắc mã hóa (theo mặc định).

Tôi không biết, nhưng tôi luôn được mã hóa sử dụng trực tiếp unicode() constructor, ít nhất đó là những cách tại official documentation:

unicode(your_str, errors="ignore") 
+0

Cảm ơn điều này đã giúp tôi. – ashim888

+1

Thao tác này sẽ loại bỏ các ký tự không phải ASCII khỏi chuỗi. ('unicode (" \ xe2 \ x9d \ xa4 ", errors = 'ignore')' cho 'u'''.) Nếu đó là kết quả chấp nhận được, thì điều này có thể không sao. Tôi không thể tưởng tượng rằng mất dữ liệu là okay trong phần lớn các tình huống, mặc dù. Ít nhất, câu trả lời này cần phải giải thích về sự phù hợp của việc đó. – jpmc26

54

đoán ở tất cả những điều bỏ qua từ câu hỏi ban đầu, nhưng, giả sử Python 2.x chìa khóa là để đọc các thông báo lỗi một cách cẩn thận: đặc biệt là nơi bạn gọi là 'mã hóa' nhưng thông báo nói 'giải mã' và ngược lại, nhưng cũng là các loại giá trị được bao gồm trong các tin nhắn.

Trong ví dụ đầu tiên string là loại unicode và bạn đã cố gắng giải mã nó là một hoạt động chuyển đổi chuỗi byte thành unicode. Python đã cố gắng chuyển đổi giá trị unicode thành str bằng cách sử dụng mã hóa 'ascii' mặc định nhưng vì chuỗi của bạn chứa ký tự không phải ascii bạn nhận được lỗi cho biết rằng Python không thể mã hóa a unicode giá trị. Dưới đây là ví dụ hiển thị loại chuỗi đầu vào:

>>> u"\xa0".decode("ascii", "ignore") 

Traceback (most recent call last): 
    File "<pyshell#7>", line 1, in <module> 
    u"\xa0".decode("ascii", "ignore") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128) 

Trong trường hợp thứ hai bạn thực hiện đảo ngược cố mã hóa chuỗi byte. Encoding là một hoạt động có thể chuyển đổi unicode thành một chuỗi byte, vì thế Python helpfully cố gắng để chuyển đổi chuỗi byte của bạn thành Unicode đầu tiên và, vì bạn không cung cấp cho nó một chuỗi ascii bộ giải mã ascii mặc định thất bại:

>>> "\xc2".encode("ascii", "ignore") 

Traceback (most recent call last): 
    File "<pyshell#6>", line 1, in <module> 
    "\xc2".encode("ascii", "ignore") 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128) 
+0

Đây là giải thích tốt nhất về vấn đề này mà tôi từng đọc. – cerberos

+0

Điều này giải thích huyền thoại. – foresightyj

21

Ngoài nhận được decodeencode ngược lại, tôi nghĩ một phần câu trả lời ở đây thực sự là không sử dụng mã hóa ascii. Nó có thể không phải là những gì bạn muốn.

Để bắt đầu, hãy nghĩ đến str giống như bạn sẽ là một tệp văn bản thuần túy. Nó chỉ là một loạt các byte mà không có mã hóa thực sự gắn liền với nó. Làm thế nào nó được giải thích là đến bất cứ phần nào của mã được đọc nó. Nếu bạn không biết đoạn văn này nói về điều gì, hãy đọc số The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets của Joel ngay bây giờ trước khi bạn tiếp tục.

Đương nhiên, chúng ta đều nhận thức được sự lộn xộn đã tạo ra. Câu trả lời là, ít nhất là trong bộ nhớ, có một mã hóa tiêu chuẩn cho tất cả các chuỗi. Đó là nơi mà unicode xuất hiện. Tôi đang gặp khó khăn khi theo dõi chính xác những gì mã hóa Python sử dụng nội bộ chắc chắn, nhưng nó không thực sự quan trọng chỉ cho việc này. Vấn đề là bạn biết đó là một chuỗi các byte được diễn giải theo một cách nhất định. Vì vậy, bạn chỉ cần suy nghĩ về các nhân vật, chứ không phải các byte.

Vấn đề là trong thực tế, bạn chạy vào cả hai.Một số thư viện cung cấp cho bạn str và một số thư viện mong đợi một số str. Chắc chắn điều đó có ý nghĩa bất cứ khi nào bạn đang phát trực tuyến một chuỗi các byte (chẳng hạn như đến hoặc từ đĩa hoặc qua yêu cầu web). Vì vậy, bạn cần để có thể dịch qua lại.

Nhập codecs: đó là thư viện bản dịch giữa hai loại dữ liệu này. Bạn sử dụng encode để tạo một chuỗi các byte (str) từ một chuỗi văn bản (unicode) và bạn sử dụng decode để nhận chuỗi văn bản (unicode) từ một chuỗi byte (str).

Ví dụ:

>>> s = "I look like a string, but I'm actually a sequence of bytes. \xe2\x9d\xa4" 
>>> codecs.decode(s, 'utf-8') 
u"I look like a string, but I'm actually a sequence of bytes. \u2764" 

gì xảy ra ở đây? Tôi đã cho Python một chuỗi các byte, và sau đó tôi đã nói với nó, "Hãy cho tôi phiên bản unicode về điều này, cho rằng chuỗi byte này là trong 'utf-8'." Nó đã làm như tôi đã hỏi, và những byte (a heart character) bây giờ được xử lý như một toàn thể, đại diện bởi codepoint Unicode của họ.

Hãy đi theo con đường khác xung quanh:

>>> u = u"I'm a string! Really! \u2764" 
>>> codecs.encode(u, 'utf-8') 
"I'm a string! Really! \xe2\x9d\xa4" 

Tôi đưa cho Python một chuỗi Unicode, và tôi hỏi nó để dịch các chuỗi thành một chuỗi các byte bằng cách sử dụng mã hóa 'utf-8'. Vì vậy, nó đã làm, và bây giờ trái tim chỉ là một bó của byte nó không thể in như ASCII; vì vậy nó cho tôi thấy hệ thập lục phân thay thế.

Chúng ta có thể làm việc với mã hóa khác cũng vậy, tất nhiên:

>>> s = "I have a section \xa7" 
>>> codecs.decode(s, 'latin1') 
u'I have a section \xa7' 
>>> codecs.decode(s, 'latin1')[-1] == u'\u00A7' 
True 

>>> u = u"I have a section \u00a7" 
>>> u 
u'I have a section \xa7' 
>>> codecs.encode(u, 'latin1') 
'I have a section \xa7' 

(. '\xa7'section character, trong cả hai Unicode và Latin-1)

Vì vậy, câu hỏi của bạn, trước tiên bạn cần phải tìm hiểu xem mã hóa số str của bạn là gì.

  • Nó đến từ tệp? Từ yêu cầu web? Từ cơ sở dữ liệu của bạn? Sau đó, nguồn xác định mã hóa. Tìm hiểu mã hóa của nguồn và sử dụng nó để dịch nó thành một unicode.

    s = [get from external source] 
    u = codecs.decode(s, 'utf-8') # Replace utf-8 with the actual input encoding 
    
  • Hoặc có thể bạn đang cố viết nó ở đâu đó. Những gì mã hóa nào các điểm đến mong đợi? Sử dụng nó để dịch nó thành một str. UTF-8 là một lựa chọn tốt cho các tài liệu văn bản thuần túy; hầu hết mọi thứ có thể đọc nó.

    u = u'My string' 
    s = codecs.encode(u, 'utf-8') # Replace utf-8 with the actual output encoding 
    [Write s out somewhere] 
    
  • Bạn chỉ cần dịch qua lại trong bộ nhớ cho khả năng tương tác hay gì đó? Sau đó, chỉ cần chọn một mã hóa và gắn bó với nó; 'utf-8' có lẽ là lựa chọn tốt nhất cho điều đó:

    u = u'My string' 
    s = codecs.encode(u, 'utf-8') 
    newu = codecs.decode(s, 'utf-8') 
    

Trong lập trình hiện đại, bạn có lẽ không bao giờ muốn sử dụng mã hóa 'ascii' cho bất kỳ này. Đó là một tập hợp con rất nhỏ của tất cả các ký tự có thể, và không có hệ thống nào tôi biết sử dụng nó theo mặc định hoặc bất cứ thứ gì.

Python 3 làm hết sức mình để làm cho điều này vô cùng rõ ràng hơn chỉ đơn giản bằng cách thay đổi tên.Trong Python 3, str được thay thế bằng bytesunicode được thay thế bằng str.

+0

Giải thích tuyệt vời !!! –

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