2012-07-05 5 views
43

Вот мои попытки с сообщениями об ошибках. Что я делаю не так?строковое кодирование и декодирование?

string.decode("ascii", "ignore") 

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

string.encode('utf-8', "ignore") 

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 37: ordinal not in range(128)

+0

Какова ценность 'string'? Какой тип? –

+0

Не имеет смысла декодировать объект Unicode, поскольку он уже находится в декодированной форме. Когда вы вызываете unicode_object.decode(), Python предполагает, что вы хотите декодировать байтовую строку в Unicode. Сначала он пытается кодировать объект Unicode как строку байта, используя стандартную кодировку вашей системы - это реальная ошибка, которую вы видите. – kumar303

ответ

74

Вы не можете декодировать unicode, и вы не можете кодировать str. Попробуйте сделать это the other way around.

+6

Точный, но, возможно, немного телеграфный, поэтому я добавил более подробное объяснение. – Duncan

+1

Мудрые слова ... Хотелось бы, чтобы я прочитал, что раньше – Remiz

+6

Я единственный, кто думает, что у Python это неверно? Когда я превращаю строку python в ее двоичное представление utf-8, наверняка это следует назвать «кодировкой», а не наоборот? –

2

Это потому, что ваша строка ввода не может быть преобразована в соответствии с правилами кодирования (по умолчанию по умолчанию).

я не знаю, но я всегда кодируются с использованием непосредственно Юникода() конструктор, по крайней мере, пути на official documentation:

unicode(your_str, errors="ignore") 
+0

Спасибо, это помогло мне. – ashim888

+1

Это удаляет символы, отличные от ASCII, из строки. ('unicode (" \ xe2 \ x9d \ xa4 ", errors = 'ignore')' дает 'u'''.) Если это приемлемый результат, тогда это может быть хорошо. Я не могу себе представить, что потеря данных в порядке вещей в большинстве ситуаций. По крайней мере, этот ответ должен разъяснять целесообразность этого. – jpmc26

54

Гадание на всех вещах, не включенных в первоначальный вопрос, но, предполагая, что Python 2.x должен внимательно прочитать сообщения об ошибках: в частности, когда вы вызываете «кодировать», но в сообщении говорится «декодировать» и наоборот, а также типы значений, включенных в сообщения.

В первом примере string имеет типа unicode и вы попытались расшифровать его, который является операцией преобразования байтовой строки в Юникоде. Python попытался преобразовать значение unicode в str, используя стандартную кодировку ascii, но так как ваша строка содержала символ не ascii, вы получили ошибку, которая говорит о том, что Python не смог установить encode a unicode значение. Вот пример, который показывает тип входной строки:

>>> u"\xa0".decode("ascii", "ignore") 

Traceback (most recent call last): 
    File "<pyshell#7>", line 1, in <module> 
    u"\xa0".decode("ascii", "ignore") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128) 

Во втором случае вы делаете наоборот пытается кодировать строку байтов. Кодирование представляет собой операцию, которая преобразует Юникода в строку байтов так Python услужливо пытается преобразовать строку байт в юникод первый и, так как вы не дали ему строку ASCII ASCII по умолчанию декодер терпит неудачу:

>>> "\xc2".encode("ascii", "ignore") 

Traceback (most recent call last): 
    File "<pyshell#6>", line 1, in <module> 
    "\xc2".encode("ascii", "ignore") 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128) 
+0

Это лучшее объяснение этой проблемы, которую я когда-либо читал. – cerberos

+0

Это объясняет миф. – foresightyj

21

Помимо получая decode и encode назад, я думаю, что часть ответа здесь на самом деле не используют кодировку ascii. Скорее всего, это не то, что вы хотите.

Для начала подумайте о str, как и в текстовом файле. Это всего лишь куча байтов без привязки к ней. То, как это интерпретируется, зависит от того, какой фрагмент кода читает его. Если вы не знаете, о чем идет речь в этом параграфе, перейдите на страницу The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets Joel прямо сейчас, прежде чем идти дальше.

Естественно, мы все знаем о создавшемся беспорядке. Ответ заключается в том, чтобы, по крайней мере, в памяти, иметь стандартную кодировку для всех строк. Вот где и находится unicode. У меня возникли проблемы с отслеживанием того, что кодирование Python использует внутренне точно, но на самом деле это не имеет значения только для этого. Дело в том, что вы знаете, что это последовательность байтов, которые интерпретируются определенным образом. Поэтому вам нужно только подумать о самих персонажах, а не о байтах.

Проблема в том, что на практике вы сталкиваетесь с обоими.Некоторые библиотеки дают вам str, а некоторые ожидают str. Разумеется, это имеет смысл всякий раз, когда вы передаете последовательность байтов (например, на диск или с помощью веб-запроса или с него). Таким образом, вы должны уметь переводить вперед и назад.

Ввод codecs: это библиотека переводов между этими двумя типами данных. Вы используете encode для генерации последовательности байтов (str) из текстовой строки (unicode), и вы используете decode для получения текстовой строки (unicode) из последовательности байтов (str).

Например:

>>> s = "I look like a string, but I'm actually a sequence of bytes. \xe2\x9d\xa4" 
>>> codecs.decode(s, 'utf-8') 
u"I look like a string, but I'm actually a sequence of bytes. \u2764" 

Что здесь произошло? Я дал Python последовательность байтов, а затем я сказал: «Дайте мне версию unicode, учитывая, что эта последовательность байтов находится в 'utf-8'». Он сделал, как я спросил, и эти байты (a heart character) теперь рассматриваются как целое, представленное их кодовым кодом Unicode.

Пойдемте наоборот:

>>> u = u"I'm a string! Really! \u2764" 
>>> codecs.encode(u, 'utf-8') 
"I'm a string! Really! \xe2\x9d\xa4" 

Я дал Python строку Unicode, и я попросил его перевести строку в последовательность байтов, используя 'utf-8' кодирование. Так оно и было, и теперь сердце - это просто куча байтов, который он не может печатать как ASCII; поэтому он показывает мне шестнадцатеричный.

Мы можем работать с другими кодировками, тоже, конечно:

>>> s = "I have a section \xa7" 
>>> codecs.decode(s, 'latin1') 
u'I have a section \xa7' 
>>> codecs.decode(s, 'latin1')[-1] == u'\u00A7' 
True 

>>> u = u"I have a section \u00a7" 
>>> u 
u'I have a section \xa7' 
>>> codecs.encode(u, 'latin1') 
'I have a section \xa7' 

(. '\xa7' является section character, как в Unicode и Latin-1)

Так ваш вопрос, вы первый необходимо выяснить, в какой кодировке ваш str находится в.

  • ли он пришел из файла? Из веб-запроса? Из вашей базы данных? Затем источник определяет кодировку. Узнайте кодировку источника и используйте его для перевода в unicode.

    s = [get from external source] 
    u = codecs.decode(s, 'utf-8') # Replace utf-8 with the actual input encoding 
    
  • Возможно, вы пытаетесь это где-то написать. Какую кодировку ожидает цель? Используйте это, чтобы перевести его в str. UTF-8 - хороший выбор для текстовых документов; большинство вещей может это прочитать.

    u = u'My string' 
    s = codecs.encode(u, 'utf-8') # Replace utf-8 with the actual output encoding 
    [Write s out somewhere] 
    
  • Вы просто переводите назад и вперед в память для взаимодействия или чего-то еще? Затем просто выберите кодировку и придерживайтесь ее; 'utf-8', вероятно, является лучшим выбором для этого:

    u = u'My string' 
    s = codecs.encode(u, 'utf-8') 
    newu = codecs.decode(s, 'utf-8') 
    

В современном программировании, вы, вероятно, никогда не хотите использовать 'ascii' кодировку для любого из этого. Это очень маленькое подмножество всех возможных символов, и никакая система, которую я знаю, не использует ее по умолчанию или что-то еще.

Python 3 делает все возможное, чтобы сделать это immensely проще, просто изменив имена.В Python 3, str был заменен на bytes, а unicode был заменен на str.

+0

Красивое объяснение !!! –

Смежные вопросы