Python: การแปลงจาก ISO-8859-1 / latin1 เป็น UTF-8


89

ฉันมีสตริงนี้ที่ถอดรหัสจาก Quoted-printable เป็น ISO-8859-1 ด้วยโมดูลอีเมล สิ่งนี้ทำให้ฉันมีสตริงเช่น "\ xC4pple" ซึ่งจะตรงกับ "Äpple" (Apple ในภาษาสวีเดน) อย่างไรก็ตามฉันไม่สามารถแปลงสตริงเหล่านั้นเป็น 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)

ฉันควรทำอย่างไรดี?

คำตอบ:


123

ลองถอดรหัสก่อนจากนั้นเข้ารหัส:

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

5
ฉันมีปัญหาในการเข้ารหัสข้อมูลเป็นภาษาของฉัน (โปรตุเกส) ดังนั้นสิ่งที่ใช้ได้ผลสำหรับฉันคือ string.decode ('iso-8859-1') เข้ารหัส ('latin1') นอกจากนี้ที่ด้านบนของไฟล์ python ฉันมี # - - coding: latin-1 - -
Moon13

151

นี่เป็นปัญหาที่พบบ่อยดังนั้นนี่คือภาพประกอบที่ค่อนข้างละเอียด

สำหรับสตริงที่ไม่ใช่ Unicode (เช่นที่ไม่มีuคำนำหน้าเช่นu'\xc4pple') ต้องถอดรหัสจากการเข้ารหัสดั้งเดิม ( iso8859-1/ latin1เว้นแต่จะแก้ไขด้วยsys.setdefaultencodingฟังก์ชันลึกลับ ) เป็นunicodeจากนั้นเข้ารหัสเป็นชุดอักขระที่สามารถแสดงอักขระที่คุณต้องการในกรณีนี้ฉัน 'd แนะนำUTF-8.

ขั้นแรกนี่คือฟังก์ชั่นยูทิลิตี้ที่มีประโยชน์ซึ่งจะช่วยให้รูปแบบของสตริง Python 2.7 และ unicode สว่างขึ้น

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

สตริงธรรมดา

>>> 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 "?".

การถอดรหัสสตริง iso8859-1 - แปลงสตริงธรรมดาเป็น 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

ภาพประกอบเพิ่มเติมอีกเล็กน้อย - พร้อม“ Ä”

>>> 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').

การเข้ารหัสเป็น 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')

ความสัมพันธ์ระหว่าง Unicode และ UTF และ 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)

ข้อยกเว้นของ 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)

หนึ่งจะได้รับรอบเหล่านี้โดยการแปลงจากการเข้ารหัสที่เฉพาะเจาะจง (ละติน-1 utf8, UTF16) เพื่อ Unicode u8.decode('utf8').encode('latin1')เช่น

บางทีเราอาจวาดหลักการและลักษณะทั่วไปดังต่อไปนี้:

  • ประเภทstrคือชุดของไบต์ซึ่งอาจมีการเข้ารหัสแบบใดแบบหนึ่งเช่น Latin-1, UTF-8 และ UTF-16
  • ประเภทunicodeคือชุดของไบต์ที่สามารถแปลงเป็นการเข้ารหัสจำนวนเท่าใดก็ได้โดยทั่วไปมักเป็น UTF-8 และละติน -1 (iso8859-1)
  • printคำสั่งมีตรรกะของตัวเองสำหรับการเข้ารหัส , ชุดsys.stdout.encodingและผิดนัด UTF-8
  • เราต้องถอดรหัส a strto unicode ก่อนที่จะแปลงเป็นการเข้ารหัสอื่น

แน่นอนการเปลี่ยนแปลงทั้งหมดนี้ใน Python 3.x.

หวังว่าจะส่องสว่าง

อ่านเพิ่มเติม

และคำพูดที่เป็นภาพประกอบโดย Armin Ronacher:


13
ขอบคุณที่สละเวลาเขียนคำอธิบายโดยละเอียดซึ่งเป็นหนึ่งในคำตอบที่ดีที่สุดที่ฉันเคยพบใน stackoverflow :)
ruyadorno

6
ว้าว. กระชับเข้าใจมากและอธิบายด้วยตัวอย่าง ขอบคุณที่ทำให้ Intertubes ดีขึ้น
Monkey Boson

24

สำหรับ Python 3:

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

ฉันใช้สิ่งนี้สำหรับข้อความที่เข้ารหัสอย่างไม่ถูกต้องเป็น iso-8859-1 (แสดงคำเช่นVeÅ \ x99ejné ) แทน utf-8 รหัสนี้ผลิตรุ่นที่ถูกต้องVeřejné


ที่ไม่bytesมาจากไหน?
alvas

1
เอกสารอ้างอิง: ไบต์ ดูคำถามนี้และคำตอบด้วย
Michal Skop

3
สำหรับไฟล์ที่ดาวน์โหลดด้วยคำขอที่มีส่วนหัวที่ขาดหายไปหรือไม่ถูกต้อง: r = requests.get(url)จากนั้นการตั้งค่าโดยตรงก็r.encoding = 'utf-8'ใช้ได้สำหรับฉัน
Michal Skop

เอกสารวิธีการbytes.decode
ไมค์

10

ถอดรหัสเป็น Unicode เข้ารหัสผลลัพธ์เป็น UTF8

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

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

ทำแบบนี้ไม่แน่ใจว่าเป็นแนวทางที่ดี แต่ใช้ได้ผลทุกครั้ง !!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.