Python генерирует UnicodeEncodeError, хотя я делаю str.decode (). Зачем? - PullRequest
4 голосов
/ 21 декабря 2011

Рассмотрим эту функцию:

def escape(text):
    print repr(text)
    escaped_chars = []
    for c in text:
        try:
            c = c.decode('ascii')
        except UnicodeDecodeError:
            c = '&{};'.format(htmlentitydefs.codepoint2name[ord(c)])
        escaped_chars.append(c)
    return ''.join(escaped_chars)

Он должен экранировать все символы не ascii соответствующими htmlentitydefs. К сожалению питон бросает

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 0: ordinal not in range(128)

когда переменная text содержит строку, repr() которой равна u'Tam\xe1s Horv\xe1th'.

Но я не использую str.encode(). Я использую только str.decode(). Я что-то пропустил?

Ответы [ 6 ]

11 голосов
/ 21 декабря 2011

Это вводящее в заблуждение сообщение об ошибке, которое происходит от того, как python обрабатывает процесс де / кодирования.Вы пытались декодировать уже декодированную строку во второй раз, и это сбивает с толку функцию Python, которая наносит ответный удар, запутывая вас по очереди!;-) Процесс кодирования / декодирования происходит, насколько я знаю, модулем кодеков.И где-то там лежит источник этих вводящих в заблуждение сообщений об исключениях.

Вы можете проверить сами: либо

u'\x80'.encode('ascii')

, либо

u'\x80'.decode('ascii')

выдаст Unicode Кодировать Ошибка, когда

u'\x80'.encode('utf8')

не будет, но

u'\x80'.decode('utf8')

снова будет!

Я думаю, вы смущены смыслом кодированияи расшифровка.Проще говоря:

                     decode             encode    
ByteString (ascii)  --------> UNICODE  --------->  ByteString (utf8)
            codec                                              codec

Но почему существует codec -аргумент для метода decode?Итак, базовая функция не может угадать, с каким кодеком была закодирована строка ByteString, так что в качестве подсказки она принимает codec в качестве аргумента.Если не указано иное, предполагается, что вы подразумеваете, что sys.getdefaultencoding() будет использоваться неявно.

поэтому, когда вы используете c.decode('ascii'), вы а) имеете (закодированную) ByteString (вот почему вы используете декодирование), б) вы хотите получить объект представления юникода (именно для этого вы используете декодирование) иc) кодек, в котором закодирована ByteString, является ASCII.

См. также: https://stackoverflow.com/a/370199/1107807
http://docs.python.org/howto/unicode.html
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
http://www.stereoplex.com/blog/python-unicode-and-unicodedecodeerror

5 голосов
/ 21 декабря 2011

Вы передаете строку, которая уже является Unicode.Таким образом, прежде чем Python сможет вызвать decode, он должен фактически закодировать его - и он делает это по умолчанию, используя кодировку ASCII.

Изменить, чтобы добавить Это зависит от того, что выхотеть сделать.Если вы просто хотите преобразовать строку Unicode с не-ASCII-символами в представление в кодировке HTML, вы можете сделать это за один вызов: text.encode('ascii', 'xmlcharrefreplace').

2 голосов
/ 27 ноября 2015

Этот ответ всегда работает для меня, когда у меня возникает такая проблема:

def byteify(input):
    '''
    Removes unicode encodings from the given input string.
    '''
    if isinstance(input, dict):
        return {byteify(key):byteify(value) for key,value in input.iteritems()}
    elif isinstance(input, list):
        return [byteify(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

из Как получить строковые объекты вместо объектов Unicode из JSON в Python?

2 голосов
/ 21 декабря 2011

Python имеет два типа строк: символьные строки (тип unicode) и байтовые строки (тип str).Вставленный вами код работает с байтовыми строками.Вам нужна аналогичная функция для обработки строк символов.

Может быть, это:

def uescape(text):
    print repr(text)
    escaped_chars = []
    for c in text:
        if (ord(c) < 32) or (ord(c) > 126):
            c = '&{};'.format(htmlentitydefs.codepoint2name[ord(c)])
        escaped_chars.append(c)
    return ''.join(escaped_chars)

Мне интересно, действительно ли любая из этих функций вам действительно необходима.Если бы это был я, я бы выбрал UTF-8 в качестве кодировки символов для результирующего документа, обработал документ в виде символьной строки (не беспокоясь о сущностях) и выполнил content.encode('UTF-8') в качестве последнего шага, прежде чем доставить его вклиент.В зависимости от выбранного веб-фреймворка вы можете даже доставлять строки символов непосредственно в API и определять, как установить кодировку.

0 голосов
/ 22 июля 2016

Я нашел решение в этом сайте

reload(sys)
sys.setdefaultencoding("latin-1")

a = u'\xe1'
print str(a) # no exception
0 голосов
/ 21 декабря 2011

decode a str не имеет смысла.

Я думаю, что вы можете проверить ord(c)>127

...