Python: Chuyển đổi từ ISO-8859-1 / latin1 sang UTF-8


87

Tôi có chuỗi này đã được giải mã từ Trích dẫn-có thể in thành ISO-8859-1 bằng mô-đun email. Điều này cho tôi các chuỗi như "\ xC4pple" tương ứng với "Äpple" (Apple trong tiếng Thụy Điển). Tuy nhiên, tôi không thể chuyển đổi các chuỗi đó thành UTF-8.

>>> apple = "\xC4pple"
>>> apple
'\xc4pple'
>>> apple.encode("UTF-8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in     range(128)

Tôi nên làm gì?

Câu trả lời:


122

Hãy thử giải mã nó trước, sau đó mã hóa:

apple.decode('iso-8859-1').encode('utf8')

5
Tôi đã gặp một số vấn đề khi mã hóa nội dung sang ngôn ngữ của mình (tiếng Bồ Đào Nha), vì vậy, thứ phù hợp với tôi là string.decode ('iso-8859-1'). Encode ('latin1'). Ngoài ra, trên đầu tệp python của tôi, tôi có # - - mã này: latin-1 - -
Moon13

149

Đây là một vấn đề phổ biến, vì vậy đây là một minh họa tương đối kỹ lưỡng.

Đối với các chuỗi không phải unicode (tức là những chuỗi không có utiền tố như u'\xc4pple'), người ta phải giải mã từ mã hóa gốc ( iso8859-1/ latin1, trừ khi được sửa đổi bằngsys.setdefaultencoding hàm bí ẩn ) unicode, sau đó mã hóa thành một bộ ký tự có thể hiển thị các ký tự bạn muốn, trong trường hợp này tôi muốn giới thiệu UTF-8.

Đầu tiên, đây là một chức năng tiện ích hữu ích sẽ giúp làm sáng tỏ các mẫu của chuỗi Python 2.7 và unicode:

>>> def tell_me_about(s): return (type(s), s)

Một chuỗi đơn giản

>>> v = "\xC4pple" # iso-8859-1 aka latin1 encoded string

>>> tell_me_about(v)
(<type 'str'>, '\xc4pple')

>>> v
'\xc4pple'        # representation in memory

>>> print v
?pple             # map the iso-8859-1 in-memory to iso-8859-1 chars
                  # note that '\xc4' has no representation in iso-8859-1, 
                  # so is printed as "?".

Giải mã chuỗi iso8859-1 - chuyển đổi chuỗi thuần thành unicode

>>> uv = v.decode("iso-8859-1")
>>> uv
u'\xc4pple'       # decoding iso-8859-1 becomes unicode, in memory

>>> tell_me_about(uv)
(<type 'unicode'>, u'\xc4pple')

>>> print v.decode("iso-8859-1")
Äpple             # convert unicode to the default character set
                  # (utf-8, based on sys.stdout.encoding)

>>> v.decode('iso-8859-1') == u'\xc4pple'
True              # one could have just used a unicode representation 
                  # from the start

Minh họa thêm một chút - với “Ä”

>>> u"Ä" == u"\xc4"
True              # the native unicode char and escaped versions are the same

>>> "Ä" == u"\xc4"  
False             # the native unicode char is '\xc3\x84' in latin1

>>> "Ä".decode('utf8') == u"\xc4"
True              # one can decode the string to get unicode

>>> "Ä" == "\xc4"
False             # the native character and the escaped string are
                  # of course not equal ('\xc3\x84' != '\xc4').

Mã hóa thành UTF

>>> u8 = v.decode("iso-8859-1").encode("utf-8")
>>> u8
'\xc3\x84pple'    # convert iso-8859-1 to unicode to utf-8

>>> tell_me_about(u8)
(<type 'str'>, '\xc3\x84pple')

>>> u16 = v.decode('iso-8859-1').encode('utf-16')
>>> tell_me_about(u16)
(<type 'str'>, '\xff\xfe\xc4\x00p\x00p\x00l\x00e\x00')

>>> tell_me_about(u8.decode('utf8'))
(<type 'unicode'>, u'\xc4pple')

>>> tell_me_about(u16.decode('utf16'))
(<type 'unicode'>, u'\xc4pple')

Mối quan hệ giữa unicode và UTF và latin1

>>> print u8
Äpple             # printing utf-8 - because of the encoding we now know
                  # how to print the characters

>>> print u8.decode('utf-8') # printing unicode
Äpple

>>> print u16     # printing 'bytes' of u16
���pple

>>> print u16.decode('utf16')
Äpple             # printing unicode

>>> v == u8
False             # v is a iso8859-1 string; u8 is a utf-8 string

>>> v.decode('iso8859-1') == u8
False             # v.decode(...) returns unicode

>>> u8.decode('utf-8') == v.decode('latin1') == u16.decode('utf-16')
True              # all decode to the same unicode memory representation
                  # (latin1 is iso-8859-1)

Ngoại lệ Unicode

 >>> u8.encode('iso8859-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
  ordinal not in range(128)

>>> u16.encode('iso8859-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0:
  ordinal not in range(128)

>>> v.encode('iso8859-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0:
  ordinal not in range(128)

Ai có thể làm được việc này bằng cách chuyển đổi từ mã hóa cụ thể (latin-1, utf8, UTF16) để unicode ví dụ u8.decode('utf8').encode('latin1').

Vì vậy, có lẽ người ta có thể rút ra các nguyên tắc và khái quát sau:

  • một loại strlà một tập hợp các byte, có thể có một trong số các mã hóa như Latin-1, UTF-8 và UTF-16
  • một loại unicodelà một tập hợp các byte có thể được chuyển đổi thành bất kỳ số lượng mã hóa nào, phổ biến nhất là UTF-8 và latin-1 (iso8859-1)
  • các printlệnh có logic riêng của nó để mã hóa , thiết lập để sys.stdout.encodingvà mặc định là UTF-8
  • Người ta phải giải mã a strthành unicode trước khi chuyển đổi sang một bảng mã khác.

Tất nhiên, tất cả những thay đổi này trong Python 3.x.

Hy vọng rằng điều đó đang sáng.

đọc thêm

Và những câu nói rất minh họa của Armin Ronacher:


12
Cảm ơn đã dành thời gian để viết như một lời giải thích chi tiết, một trong những câu trả lời tốt nhất mà tôi từng được tìm thấy trên stackoverflow :)
ruyadorno

5
Chà. Succinct, rất dễ hiểu và được giải thích bằng ví dụ. Cảm ơn vì đã làm cho Intertubes tốt hơn.
Monkey Boson

22

Đối với Python 3:

bytes(apple,'iso-8859-1').decode('utf-8')

Tôi đã sử dụng điều này cho một văn bản được mã hóa không chính xác thành iso-8859-1 (hiển thị các từ như VeÅ \ x99ejnà © ) thay vì utf-8. Mã này tạo ra phiên bản chính xác Veřejné .


nơi nào bytesđến từ đâu?
alvas

1
Tài liệu: byte . Cũng xem câu hỏi này và câu trả lời của nó.
Michal Skop

3
Cho các tập tin được tải về với yêu cầu với thiếu hoặc tiêu đề không đúng: r = requests.get(url)và sau đó trực tiếp đặt cài r.encoding = 'utf-8'làm việc cho tôi
Michal Skop

tài liệu phương pháp bytes.decode .
mike

10

Giải mã sang Unicode, mã hóa kết quả thành UTF8.

apple.decode('latin1').encode('utf8')

0
concept = concept.encode('ascii', 'ignore') 
concept = MySQLdb.escape_string(concept.decode('latin1').encode('utf8').rstrip())

Tôi làm điều này, tôi không chắc đó có phải là một cách tiếp cận tốt hay không nhưng nó hoạt động mọi lúc !!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.