[python] 수정 방법 :“UnicodeDecodeError : ‘ascii’코덱이 바이트를 디코딩 할 수 없습니다 ‘

as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

고치는 방법?

다른 파이썬 기반 정적 블로그 앱에서 중국어 게시물을 성공적으로 게시 할 수 있습니다. 이 응용 프로그램과 같은 : http://github.com/vrypan/bucket3 . 내 사이트 http://bc3.brite.biz/ 에서 중국어 게시물을 성공적으로 게시 할 수 있습니다.



답변

tl; dr / 빠른 수정

  • Willy Nilly를 디코딩 / 인코딩하지 마십시오
  • 문자열이 UTF-8로 인코딩되어 있다고 가정하지 마십시오
  • 코드에서 가능한 빨리 문자열을 유니 코드 문자열로 변환하십시오.
  • 로케일을 수정하십시오. Python 3.6에서 UnicodeDecodeError를 해결하는 방법?
  • 빠른 reload해킹 을 사용하려는 유혹을받지 마십시오

Python 2.x의 유니 코드 젠-긴 버전

소스를 보지 않으면 근본 원인을 알기가 어렵 기 때문에 일반적으로 말해야합니다.

UnicodeDecodeError: 'ascii' codec can't decode byte 일반적으로 Python 2.x를 변환하려고 할 때 발생합니다. str 원래 문자열의 인코딩을 지정하지 않고 비 ASCII가 포함 를 유니 코드 문자열 합니다.

간단히 말해서, 유니 코드 문자열은 인코딩을 포함하지 않는 완전히 분리 된 유형의 파이썬 문자열입니다. 유니 코드 포인트 코드 만 보유 하므로 전체 스펙트럼에서 유니 코드 포인트를 보유 할 수 있습니다. 인코딩 된 텍스트 스트링을 포함 베이트 UTF-8, UTF-16, ISO-8895-1, GBK, 등의 Big5 문자열이 유니 코드 디코딩문자열로 인코딩 Unicodes . 파일과 텍스트 데이터는 항상 인코딩 된 문자열로 전송됩니다.

Markdown 모듈 작성자 unicode()는 나머지 코드의 품질 게이트로 예외 (예외가 발생한 경우)를 사용합니다. ASCII를 변환하거나 기존 유니 코드 문자열을 새 유니 코드 문자열로 다시 랩핑합니다. Markdown 작성자는 들어오는 문자열의 인코딩을 알 수 없으므로 Markdown으로 전달하기 전에 문자열을 유니 코드 문자열로 디코딩해야합니다.

문자열에 u접두사를 사용하여 코드에서 유니 코드 문자열을 선언 할 수 있습니다 . 예 :

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

유니 코드 문자열은 파일, 데이터베이스 및 네트워크 모듈에서 올 수도 있습니다. 이 경우 인코딩에 대해 걱정할 필요가 없습니다.

잡았다

str명시 적으로 호출하지 않아도 유니 코드 에서 유니 코드로 변환 할 수 있습니다 unicode().

다음과 같은 시나리오에서는 UnicodeDecodeError예외가 발생합니다.

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'         

다음 다이어그램 café에서 터미널 유형에 따라 단어 가 “UTF-8″또는 “Cp1252″인코딩으로 인코딩 된 방식을 볼 수 있습니다. 두 예에서 모두 caf규칙적인 ASCII입니다. UTF-8에서는 é2 바이트를 사용하여 인코딩됩니다. “Cp1252″에서 é는 0xE9입니다 (이는 유니 코드 포인트 값이기도합니다 (우연의 일치가 아님)). 올바른 decode()것이 호출되고 Python 유니 코드로 변환이 성공합니다.
파이썬 유니 코드 문자열로 변환되는 문자열 다이어그램

이 다이어그램에서 decode()로 호출됩니다 ascii( unicode()인코딩없이 호출하는 것과 동일 ). ASCII는보다 큰 바이트를 포함 할 수 없으므로 예외 0x7FUnicodeDecodeError발생합니다.

인코딩이 잘못된 Python 유니 코드 문자열로 변환되는 문자열 다이어그램

유니 코드 샌드위치

들어오는 모든 데이터를 유니 코드 문자열로 디코딩하고 유니 코드로 작업 한 다음 str나가는 길로 인코딩하는 코드에 유니 코드 샌드위치를 ​​형성하는 것이 좋습니다 . 이렇게하면 코드 중간에 문자열 인코딩을 걱정할 필요가 없습니다.

입력 / 디코딩

소스 코드

비 ASCII를 소스 코드에 구워야하는 경우 문자열 앞에 접두사를 붙여 유니 코드 문자열을 만드십시오 u. 예 :

u'Zürich'

파이썬이 소스 코드를 해독 할 수있게하려면 파일의 실제 인코딩과 일치하도록 인코딩 헤더를 추가해야합니다. 예를 들어 파일이 ‘UTF-8’로 인코딩 된 경우 다음을 사용합니다.

# encoding: utf-8

소스 코드 에 비 ASCII가있는 경우에만 필요 합니다 .

파일

일반적으로 비 ASCII 데이터는 파일에서 수신됩니다. 이 io모듈은 지정된을 사용하여 파일을 즉시 디코딩하는 TextWrapper를 제공합니다 encoding. 파일에 올바른 인코딩을 사용해야합니다. 쉽게 추측 할 수 없습니다. 예를 들어, UTF-8 파일의 경우 :

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
     my_unicode_string = my_file.read() 

my_unicode_string그런 다음 Markdown으로 전달하기에 적합합니다. 경우 UnicodeDecodeError로부터 read()라인, 그때는 아마 잘못된 인코딩 값을 사용했습니다.

CSV 파일

Python 2.7 CSV 모듈은 비 ASCII 문자를 지원하지 않습니다. 그러나 https://pypi.python.org/pypi/backports.csv의 도움이 필요 합니다.

위와 같이 사용하지만 열린 파일을 전달하십시오.

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
    for row in csv.reader(my_file):
        yield row

데이터베이스

대부분의 Python 데이터베이스 드라이버는 유니 코드로 데이터를 반환 할 수 있지만 일반적으로 약간의 구성이 필요합니다. SQL 쿼리에는 항상 유니 코드 문자열을 사용하십시오.

MySQL

연결 문자열에서 다음을 추가하십시오.

charset='utf8',
use_unicode=True

예 :

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")

PostgreSQL

더하다:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

웹 페이지는 거의 모든 인코딩으로 인코딩 될 수 있습니다. Content-type헤더는 포함해야 charset부호화 암시하는 필드. 그런 다음이 값에 대해 내용을 수동으로 디코딩 할 수 있습니다. 또는 Python-Requests 는에서 유니 코드를 반환합니다 response.text.

수동으로

문자열을 수동으로 디코딩해야하는 경우 적절한 인코딩이있는 my_string.decode(encoding)encoding이면됩니다. Python 2.x 지원 코덱은 다음과 같습니다. Standard Encodings . 다시 말하지만, UnicodeDecodeError인코딩이 잘못되었을 수 있습니다.

샌드위치 고기

일반적인 str과 마찬가지로 유니 코드로 작업하십시오.

산출

표준 출력 / 인쇄

printstdout 스트림을 통해 씁니다. 파이썬은 유니 코드가 콘솔의 인코딩으로 인코딩되도록 stdout에서 인코더를 구성하려고 시도합니다. 예를 들어, Linux 쉘 localeen_GB.UTF-8인 경우 출력은로 인코딩됩니다 UTF-8. Windows에서는 8 비트 코드 페이지로 제한됩니다.

손상된 로캘과 같이 잘못 구성된 콘솔은 예기치 않은 인쇄 오류로 이어질 수 있습니다. PYTHONIOENCODING환경 변수는 stdout 인코딩을 강제 할 수 있습니다.

파일

입력과 마찬가지로 io.open유니 코드를 인코딩 된 바이트 문자열로 투명하게 변환하는 데 사용할 수 있습니다.

데이터 베이스

동일한 읽기 구성으로 유니 코드를 직접 작성할 수 있습니다.

파이썬 3

Python 3은 더 이상 Python 2.x보다 유니 코드를 사용할 수 없지만 주제에 대해 약간 덜 혼동됩니다. 예를 들어 일반 str은 이제 유니 코드 문자열이고 이전 str은 이제 bytes입니다.

기본 인코딩은 UTF-8이므로 .decode()인코딩하지 않고 바이트 문자열을 사용하면 Python 3은 UTF-8 인코딩을 사용합니다. 이것은 아마도 사람들의 유니 코드 문제의 50 %를 해결합니다.

또한 open()기본적으로 텍스트 모드에서 작동하므로 디코딩 된 str(유니 코드 것)을 반환합니다 . 인코딩은 로케일에서 파생되며, Un * x 시스템의 UTF-8 또는 Windows 상자의 windows-1251와 같은 8 비트 코드 페이지입니다.

왜 사용하지 않아야 하는가 sys.setdefaultencoding('utf8')

reload문제를 가리고 Python 3.x 로의 마이그레이션을 방해 하는 불쾌한 해킹입니다 (사용해야하는 이유가 있습니다 ). 문제를 이해하고 근본 원인을 해결하고 유니 코드 선을 즐기십시오. py 스크립트에서 sys.setdefaultencoding ( “utf-8”)을 사용하지 않아야하는 이유를 참조하십시오 . 자세한 내용은


답변

마침내 나는 그것을 얻었다 :

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys

reload(sys)
sys.setdefaultencoding('utf8')

내가 체크해 볼게:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec  6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

위의 python의 기본 인코딩은입니다 utf8. 그렇다면 오류는 더 이상 없습니다.


답변

이것은 고전적인 “유니 코드 문제”입니다. 나는 이것을 설명하는 것이 무슨 일인지 완전히 설명하기 위해 StackOverflow 답변의 범위를 벗어난 것이라고 생각합니다.

여기에 잘 설명되어 있습니다 .

간단히 요약하면 바이트 문자열로 해석되는 것을 유니 코드 문자로 디코딩해야하는 것으로 전달했지만 기본 코덱 (ascii)은 실패합니다.

이것을 피하기위한 조언을 해주겠다고 지시 한 프레젠테이션. 코드를 “유니 코드 샌드위치”로 만드십시오. 파이썬 2에서는 from __future__ import unicode_literals도움을 사용 합니다.

업데이트 : 코드를 수정하는 방법 :

OK – 변수 “source”에 약간의 바이트가 있습니다. 귀하의 질문에 그들이 어떻게 들어 왔는지는 분명하지 않습니다. 아마도 웹 양식에서 읽을 수 있습니까? 어쨌든 그들은 ascii로 인코딩되지 않지만 파이썬은 그것들을 가정하여 유니 코드로 변환하려고합니다. 인코딩이 무엇인지 명시 적으로 알려 주어야합니다. 이것은 인코딩이 무엇인지 알아야 한다는 것을 의미합니다 ! 항상 쉬운 것은 아니며이 문자열의 출처에 전적으로 달려 있습니다. UTF-8과 같은 일반적인 인코딩을 실험 해 볼 수 있습니다. unicode ()에게 두 번째 매개 변수로 인코딩을 알려줍니다.

source = unicode(source, 'utf-8')


답변

경우에 따라 기본 인코딩 ( print sys.getdefaultencoding()) 을 확인 하면 ASCII를 사용하고 있음을 반환합니다. UTF-8로 변경하면 변수의 내용에 따라 작동하지 않습니다. 다른 방법을 찾았습니다.

import sys
reload(sys)
sys.setdefaultencoding('Cp1252')


답변

다음 오류 메시지를 해결하기 위해 검색했습니다.

unicodedecodeerror : ‘ascii’코덱이 5454 위치에서 바이트 0xe2를 디코딩 할 수 없습니다 : 서 수가 범위 내에 있지 않습니다 (128)

마침내 ‘encoding’을 지정하여 수정했습니다.

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

그것이 당신을 도울 수 있기를 바랍니다.


답변

"UnicodeDecodeError: 'ascii' codec can't decode byte"

이 오류의 원인 : input_string은 유니 코드 여야하지만 str이 제공되었습니다.

"TypeError: Decoding Unicode is not supported"

이 오류의 원인 : 유니 코드 input_string을 유니 코드로 변환하려고합니다.


따라서 먼저 input_string이 있는지 확인하고 str필요한 경우 유니 코드로 변환하십시오.

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

둘째, 위의 유형 만 변경하지만 ASCII가 아닌 문자는 제거하지 않습니다. ASCII가 아닌 문자를 제거하려는 경우 :

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.

elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')


답변

나는 항상 유니 코드로 변환하는 것이 가장 좋다는 것을 알지만 실제로는 모든 인수를 확인하고 문자열 처리 형식을 포함하는 모든 함수 및 메소드로 변환해야하기 때문에 달성하기가 어렵습니다.

그래서 두 입력 중 하나에서 유니 코드 또는 바이트 문자열을 보장하기 위해 다음과 같은 접근법을 생각해 냈습니다. 간단히 말해 다음 람다를 포함하여 사용 하십시오.

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt)
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

예 :

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

이것에 대한 몇 가지 추론이 있습니다.