Python - 'ascii' codec bileşeni bayt kodunu çözemez


119

Gerçekten kafam karıştı. Kodlamayı denedim ama hata dedi can't decode....

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

Dizede "u" ön eki olan hatayı nasıl önleyeceğimi biliyorum. Kodlama çağrıldığında hatanın neden "çözülemiyor" olduğunu merak ediyorum. Python kaputun altında ne yapıyor?

Yanıtlar:


167
"你好".encode('utf-8')

encodeUnicode nesnesini bir stringnesneye dönüştürür . Ama burada onu bir stringnesnede çağırdınız (çünkü u'ya sahip değilsiniz). Yani python önce nesneyi stringbir unicodenesneye dönüştürmelidir . Yani eşdeğerini yapar

"你好".decode().encode('utf-8')

Ancak dize geçerli ascii olmadığından kod çözme işlemi başarısız olur. Bu yüzden deşifre edememe konusunda şikayet alıyorsun.


50
Peki çözüm nedir? Özellikle bir dizgem yoksa, sadece bir string nesnem var.
Jon Tirsen 13

2
@JonTirsen, bir string nesnesini kodlamamalısın. Bir dizgi nesnesi zaten kodlanmış. Kodlamayı değiştirmeniz gerekirse, kodunu bir unicode dizesi olarak çözmeniz ve ardından bunu istenen kodlama olarak kodlamanız gerekir.
Winston Ewert

20
Yani yukarıdan açıkça belirtmek için şunları yapabilirsiniz"你好".decode('utf-8').encode('utf-8')
deinonychusaur

5
@WinstonEwert Sanırım kafam karıştı. Kodlama işi beni sonsuza dek kafamı karıştırmaya meyilli. Sanırım kafa karışıklığım, girdinin bir dizge mi yoksa unicode dizge mi olduğunu ve hangi kodlamaya sahip olabileceğini bilmeme sorunumdan kaynaklandı.
deinonychusaur

@deinonychusaur, evet ... Anladım.
Winston Ewert

53

Her zaman unicode'dan baytlara kodlayın .
Bu yönde kodlamayı seçersiniz .

>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好

Diğer yol, baytlardan unicode'a kod çözmektir.
Bu yönde kodlamanın ne olduğunu bilmelisiniz .

>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好

Bu nokta yeterince vurgulanamaz. Unicode "köstebek vurma" oynamaktan kaçınmak istiyorsanız, veri düzeyinde neler olduğunu anlamak önemlidir. Burada başka bir şekilde açıklanıyor:

  • Bir unicode nesnesinin kodu çözülmüştür, onu asla çağırmak istemezsiniz decode.
  • Bir bytestring nesnesi zaten kodlanmıştır, onu asla çağırmak istemezsiniz encode.

Şimdi, .encodebir bayt dizesini gördükten sonra, Python 2 önce onu örtük olarak metne (bir unicodenesne) dönüştürmeye çalışır . Benzer şekilde, .decodebir unicode dizesini gördükten sonra, Python 2 örtük olarak onu bayta (bir strnesne) dönüştürmeye çalışır .

Alabileceğiniz neden Bunlar örtük dönüşümler dediğiniz zaman . Bunun nedeni, kodlamanın genellikle bir tür parametresini kabul etmesidir ; bir parametre alırken , başka bir kodlamayla yeniden kodlamadan önce bir nesne türünde örtük bir kod çözme vardır . Bu dönüştürme, varsayılan bir 'ascii' kod çözücüyü seçer ve size bir kodlayıcı içinde kod çözme hatası verir.UnicodeDecodeErrorencodeunicodestrunicode

Aslında, Python 3'te yöntemler var str.decodeve bytes.encodeyok bile. Onların kaldırılması, bu yaygın kafa karışıklığını önlemek için [tartışmalı] bir girişimdi.

... veya kodlama ne sys.getdefaultencoding()diyorsa; genellikle bu "ascii" dir


Öyleyse, Python'un kodlamadan önce bytestring'in kodunu çözdüğünü mü söylüyorsunuz?
thoslin

@thoslin tam olarak, daha fazla ayrıntı ekledim.
wim

_ Nedir ve basılı ifadelerinizde neden parantez eksik?
NoBugs

1
@NoBugs 1. REPL'de _, bir önceki değeri ifade eder 2. çünkü bu bir python-2.x sorusudur.
wim

40

Bunu deneyebilirsin

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

Veya

Aşağıdakileri de deneyebilirsiniz

.Py dosyanızın en üstüne aşağıdaki satırı ekleyin.

# -*- coding: utf-8 -*- 

8

Python <3 kullanıyorsanız, yorumlayıcıya dize değişmezinizin Unicode olduğunu ve önüne biru :

Python 2.7.2 (default, Jan 14 2012, 23:14:09) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

Daha fazla okuma : Unicode NASIL .


4
Bir dizeyi kodluyorsanız, neden kod çözme hatası veriyor?
MxLDevs

3

u"你好".encode('utf8')Unicode dizesini kodlamak için kullanırsınız . Ama temsil etmek istiyorsanız "你好", onu çözmelisiniz. Tıpkı:

"你好".decode("utf8")

İstediğini alacaksın. Belki kodlama ve kod çözme hakkında daha fazla şey öğrenmelisiniz.


3

Unicode ile uğraşıyorsanız, bazen bunun yerine encode('utf-8')özel karakterleri görmezden gelmeyi deneyebilirsiniz, örn.

"你好".encode('ascii','ignore')

veya something.decode('unicode_escape').encode('ascii','ignore')burada önerildiği gibi .

Bu örnekte özellikle kullanışlı değildir, ancak bazı özel karakterleri dönüştürmek mümkün olmadığında diğer senaryolarda daha iyi çalışabilir.

Alternatif olarak, kullanarak belirli bir karakteri değiştirmeyireplace() düşünebilirsiniz .


1

Python yorumlayıcısını Linux veya benzeri sistemlerde (BSD, Mac hakkında emin değil) bir kabuktan başlatıyorsanız, kabuk için varsayılan kodlamayı da kontrol etmelisiniz.

Kabuktan arayın locale charmap(python yorumlayıcısından değil) ve görmelisiniz

[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

Durum böyle değilse ve başka bir şey görürseniz, örneğin

[user@host dir] $ locale charmap
ANSI_X3.4-1968
[user@host dir] $ 

Python (en azından benimki gibi bazı durumlarda) kabuğun kodlamasını miras alacak ve unicode karakterlerini yazdıramayacaktır (bazıları? Tümü?). Python'un kendi varsayılan gördüğünüz kodlama ve üzeri kontrolü sys.getdefaultencoding()ve sys.setdefaultencoding()göz ardı bu durumda olduğunu.

Bu sorunu yaşadığınızı fark ederseniz, bunu şu şekilde çözebilirsiniz:

[user@host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

(Veya alternatif olarak en_EN yerine istediğiniz tuş eşlemini seçin.) Bunu düzeltmek için de düzenleyebilirsiniz /etc/locale.conf(veya sisteminizdeki yerel ayar tanımını hangi dosya yönetiyorsa).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.