Python: Mengonversi dari ISO-8859-1 / latin1 ke UTF-8


89

Saya memiliki string ini yang telah diterjemahkan dari Quoted-printable ke ISO-8859-1 dengan modul email. Ini memberi saya string seperti "\ xC4pple" yang akan sesuai dengan "Äpple" (Apple dalam bahasa Swedia). Namun, saya tidak dapat mengonversi string tersebut ke 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)

Apa yang harus saya lakukan?

Jawaban:


123

Coba decoding terlebih dahulu, lalu encoding:

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

5
Saya mengalami masalah pengkodean barang ke bahasa saya (Portugis), jadi yang berhasil untuk saya adalah string.decode ('iso-8859-1'). Encode ('latin1'). Juga, di bagian atas file python saya, saya memiliki ini # - - coding: latin-1 - -
Moon13

151

Ini adalah masalah umum, jadi inilah ilustrasi yang relatif menyeluruh.

Untuk string non-unicode (yaitu yang tanpa uawalan seperti u'\xc4pple'), seseorang harus mendekode dari pengkodean asli ( iso8859-1/ latin1, kecuali dimodifikasi dengansys.setdefaultencoding fungsi enigmatik ) ke unicode, kemudian menyandikan ke kumpulan karakter yang dapat menampilkan karakter yang Anda inginkan, dalam hal ini saya akan merekomendasikan UTF-8.

Pertama, berikut adalah fungsi utilitas praktis yang akan membantu menerangi pola string dan unicode Python 2.7:

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

Benang polos

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

Mendekode string iso8859-1 - ubah string biasa menjadi 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

Sedikit lebih banyak ilustrasi - dengan "Ä"

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

Pengkodean ke 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')

Hubungan antara unicode dan UTF dan 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)

Pengecualian 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)

Seseorang akan menyiasatinya dengan mengubah dari pengkodean tertentu (latin-1, utf8, utf16) ke unicode misalnya u8.decode('utf8').encode('latin1').

Jadi mungkin seseorang dapat menarik prinsip dan generalisasi berikut:

  • type stradalah sekumpulan byte, yang mungkin memiliki salah satu dari sejumlah encoding seperti Latin-1, UTF-8, dan UTF-16
  • tipe unicodeadalah sekumpulan byte yang dapat dikonversi ke sejumlah penyandiaksaraan, paling umum UTF-8 dan latin-1 (iso8859-1)
  • yang printperintah memiliki logika sendiri untuk encoding , set ke sys.stdout.encodingdan default ke UTF-8
  • Seseorang harus mendekode a strmenjadi unicode sebelum mengonversi ke pengkodean lain.

Tentu saja, semua ini berubah pada Python 3.x.

Harapan itu mencerahkan.

Bacaan lebih lanjut

Dan kata-kata kasar yang sangat ilustratif oleh Armin Ronacher:


13
Terima kasih telah meluangkan waktu untuk menulis penjelasan yang begitu mendetail, salah satu jawaban terbaik yang pernah saya temukan di stackoverflow :)
ruyadorno

6
Wow. Ringkas, sangat mudah dimengerti, dan dijelaskan dengan contoh. Terima kasih telah membuat Intertubes menjadi lebih baik.
Monkey Boson

24

Untuk Python 3:

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

Saya menggunakan ini untuk teks yang salah dikodekan sebagai iso-8859-1 (menunjukkan kata-kata seperti VeÅ \ x99ejnà © ) dan bukan utf-8. Kode ini menghasilkan versi Veřejné yang benar .


darimana bytesasalnya
alvas

1
Dokumentasi: byte . Lihat juga pertanyaan ini dan jawabannya.
Michal Skop

3
Untuk file yang diunduh dengan Permintaan dengan tajuk yang hilang atau salah: r = requests.get(url)dan kemudian pengaturan langsung r.encoding = 'utf-8'berfungsi untuk saya
Michal Skop

dokumentasi metode bytes.decode .
mike

10

Decode ke Unicode, encode hasil ke UTF8.

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

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

Saya melakukan ini, saya tidak yakin apakah itu pendekatan yang baik tetapi berhasil setiap saat !!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.