Python UnicodeDecodeError - Я неправильно понимаю кодировку?

Есть мысли о том, почему это не работает? Я действительно думал, что «игнорировать» будет правильным решением.

>>> 'add \x93Monitoring\x93 to list '.encode('latin-1','ignore')
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 4: ordinal not in range(128)

person Greg    schedule 15.12.2008    source источник
comment
Я также написал длинный блог на эту тему: Проблемы с Юникодом и как с ним работать   -  person Gregg Lind    schedule 08.01.2009


Ответы (4)


... не зря их называют "кодировками" ...

Небольшая преамбула: считайте юникод нормой или идеальным состоянием. Юникод - это просто таблица символов. №65 - заглавная латинская буква A. №937 - греческая заглавная буква омега. Только то.

Чтобы компьютер мог хранить и / или управлять Unicode, он должен кодировать его в байтах. Самая простая кодировка Unicode - UCS-4; каждый символ занимает 4 байта, и доступны все ~ 1000000 символов. 4 байта содержат номер символа в таблицах Unicode в виде 4-байтового целого числа. Еще одна очень полезная кодировка - UTF-8, которая может кодировать любой символ Unicode от одного до четырех байтов. Но есть также некоторые ограниченные кодировки, такие как "latin1", которые включают очень ограниченный набор символов, в основном используемых в западных странах. Такие кодировки используют только один байт на символ.

В принципе, Unicode можно закодировать с помощью множества кодировок, а закодированные строки можно декодировать в Unicode. Дело в том, что Unicode появился довольно поздно, поэтому все мы, выросшие с использованием 8-битного набора символов, слишком поздно узнали, что все это время мы работали с закодированными строками. Кодировка может быть ISO8859-1, или Windows CP437, или CP850, или, или, или, в зависимости от нашей системы по умолчанию.

Поэтому, когда в исходном коде вы вводите строку «добавить« Мониторинг »в список» (и я думаю, вам нужна строка «добавить« Мониторинг »в список», обратите внимание на вторую цитату), вы фактически уже используете строку закодировано в соответствии с кодовой страницей вашей системы по умолчанию (байтом \ x93, я предполагаю, что вы используете кодовую страницу Windows 1252, «Western»). Если вы хотите получить Unicode из этого, вам нужно декодировать строку из кодировки "cp1252".

Итак, вы хотели сделать следующее:

"add \x93Monitoring\x94 to list".decode("cp1252", "ignore")

К сожалению, Python 2.x также включает .encode метод для строк; это удобная функция для «специальных» кодировок, таких как «zip», «rot13» или «base64», которые не имеют ничего общего с Unicode.

В любом случае, все, что вам нужно помнить для постоянных преобразований Unicode, это:

  • строка Unicode кодируется в строку Python 2.x (фактически, последовательность байтов)
  • строка Python 2.x декодируется в строку Unicode

В обоих случаях необходимо указать кодировку, которая будет использоваться.

Мне не очень понятно, я хочу спать, но очень надеюсь, что помогу.

PS Юмористическое примечание: у майя не было Unicode; древние римляне, древние греки, древние египтяне тоже этого не сделали. Все они имели свои собственные «кодировки» и почти не уважали другие культуры. Все эти цивилизации рассыпались в прах. Подумайте, люди! Сделайте свои приложения совместимыми с Unicode на благо человечества. :)

PS2 Пожалуйста, не портите предыдущее сообщение словами «Но китайцы…». Однако, если вы чувствуете склонность или обязанность сделать это, отложите это, подумав, что Unicode BMP заполнен в основном китайскими идеограммами, следовательно, китайский язык является основой Unicode. Я могу продолжать придумывать возмутительную ложь, пока люди разрабатывают приложения с поддержкой Unicode. Ваше здоровье!

person tzot    schedule 16.12.2008
comment
Юникод - это не просто таблица символов, например, один абстрактный символ может быть представлен последовательностью кодовых точек: латинская заглавная буква g с острым ударением (соответствующий кодированный символ u \ u01F4 или '') представлена ​​последовательностью u \ u0047 \ u0301 (или "Ǵ"). is.gd/eTLi- - person jfs; 08.01.2009
comment
@ J.F. Себастьян: нет, Unicode - это не просто таблица символов. Я слишком упростил вещи только для этого ответа. - person tzot; 06.01.2010
comment
Хороший ответ парень с Омегой в его имени. Я просто ответил на аналогичный вопрос, но не видел вашего ответа пока нет. - person jpsimons; 12.07.2010
comment
Кроме того, я считаю, что UTF-8 использует от 1 до 6 байтов. Возможны 2 ^ 32 символа, но сама кодировка имеет некоторые накладные расходы на отслеживание длины многобайтовой последовательности. - person jpsimons; 12.07.2010
comment
@darkporter: да, UTF-8 теоретически может использовать до 6 байтов, если стандарт Unicode использует полный 32-битный диапазон для символов. Однако в настоящее время максимальный символ Unicode - U + 10FFFF, и все символы Unicode требуют максимум 4 байта при кодировании как UTF-8. - person tzot; 12.07.2010
comment
@system: в большинстве операционных систем, отличных от Windows, идеальная строка Unicode представлена ​​в кодировке UTF-32, тогда как в системах MS Windows она представлена ​​в кодировке UCS-2 (или, возможно, UTF-16, если сейчас есть какая-то разница и, если MS в настоящее время правильно поддерживает суррогатные пары.) Что вы возражаете и где неправильная концепция? - person tzot; 08.03.2011
comment
@system: точно так же, как SQLite в том примере, вы думаете, что работаете со строками Unicode, вы думаете, что хранить их как Unicode в базе данных, но есть много слоев, о которых вы не знаете. Итак, еще раз: компьютеру необходимо закодировать строку Unicode в байты, прежде чем он что-либо с ней сделает. - person tzot; 08.03.2011
comment
Очень полезной общей статьей по UTF-8 является Что такое UTF-8 и Почему это важно?. - person tzot; 08.03.2011
comment
Приведенное выше описание неверно. На пути к вашей программе вы декодируете внешние байтовые последовательности UTF-something во внутренние строки Python Unicode, содержащие логические символы, а затем, позже, на выходе из вашей программы, вы кодируете те абстрактные строки Unicode Python в байтовые последовательности UTF-ничего. Не наоборот. - person tchrist; 30.08.2011
comment
@tchrist: Я не понимаю, в чем разница между тем, что вы пишете, и тем, что написал я. Хотите точно указать, где, по вашему мнению, я описал вещи «наоборот»? - person tzot; 30.08.2011
comment
Строки Unicode не «кодируются в строку Python», если только вы не имеете в виду смысл str. Строки внешних строк байтов UTF-something декодируются в строку Python Unicode на входе, а затем строки Python Unicode кодируются в некоторые UTF-something на выходе. env PYTHONIOENCODING=utf8 python -c 'print("Jose\u0301")' печатает José. - person tchrist; 30.08.2011
comment
@tchrist: двух выделенных строк в моем ответе должно быть достаточно, чтобы прояснить ваше «если только возможно» (обратите внимание, что они упоминают Python 2.x). Пожалуйста, воздержитесь от неправильной оценки любого текста, если вы не прочитали его и не попробовали сначала. Также обратите внимание, что кодировки не ограничиваются UTF-something (например, Windows и их кодировки CP ####) при преобразованиях ввода и вывода. - person tzot; 30.08.2011
comment
«Если только не может быть» вряд ли ясно; отсюда и мой первоначальный комментарий. Я бы хотел, чтобы вы использовали escape-последовательности кода, чтобы было ясно, когда вы говорите о внутреннем типе Python, а не только о обычном английском слове. Кроме того, я использую Python 3, а не Python 2. - person tchrist; 30.08.2011
comment
@tchrist: В 2008 году Python 3 был гораздо менее распространен, чем сегодня, и все же я отметил, что мой ответ был о Python 2, хотя это подразумевается исключением, указанным в исходном вопросе. - person tzot; 31.08.2011
comment
Относительно древних культур и отсутствия в них юникода: העבריים הקדמונים הסתדרו ללא יוניקוד, אך אכן פוזרו לכל קצות העולם. רנו הביתה רק באותה תקופה שבאה הומצאה היוניקוד! - person dotancohen; 29.12.2013

encode доступен для строк Unicode, но строка, которая у вас там, не кажется Unicode (попробуйте с u'add \ x93Monitoring \ x93 to list ')

>>> u'add \x93Monitoring\x93 to list '.encode('latin-1','ignore')
'add \x93Monitoring\x93 to list '
person rob    schedule 15.12.2008
comment
ну, строка поступает таким образом как не юникод. Итак, мне нужно что-то сделать со строкой. - person Greg; 15.12.2008
comment
Это означает, что полученная строка уже закодирована. В приведенном ниже примере вы просто декодируете и снова кодируете - предполагая кодировку latin-1 (и это не всегда может быть правдой). Я думаю, вы можете просто продолжить со своей строкой и позволить выходу обрабатывать ее правильно. - person rob; 15.12.2008

И волшебная линия:

unicodedata.normalize('NFKD', text).encode('utf-8', 'ignore')

Один лайнер, который не будет вызывать исключения, когда это больше всего необходимо (удалите плохие символы Unicode ...)

person Community    schedule 01.07.2020

Кажется, это работает:

'add \x93Monitoring\x93 to list '.decode('latin-1').encode('latin-1')

Есть проблемы с этим? Интересно, когда появляется «игнорировать», «заменить» и другие подобные способы обработки ошибок кодирования?

person Greg    schedule 15.12.2008
comment
Он появляется, когда вы хотите закодировать строку Unicode, содержащую кодовые точки, которые не могут быть представлены в выбранной вами кодировке, то есть китайские символы в latin1. Затем вы можете указать, как кодировка должна реагировать на такие кодовые точки. - person ; 15.12.2008
comment
Как сказано выше, это ничего не делает. Вы проходите через функцию, а затем наоборот. Последняя строка в лучшем случае такая же, как и исходная; в худшем случае у вас будут проблемы, подобные тем, которые изложил Хейко. - person rob; 15.12.2008
comment
Кажется, работает ?? str_object.decode ('latin1'). encode ('latin1') == str_object ДЛЯ ВСЕХ ОБЪЕКТОВ STR. Другими словами, он ничего не делает. - person John Machin; 26.11.2009
comment
Это ничего не делает для Latin-1. Это отличается от кодировок, для которых произвольные последовательности байтов не всегда допустимы или имеют несколько кодировок одного и того же символа. - person dan04; 13.08.2010
comment
Если вам нужно выполнить руководство encode и / или decode, вы делаете что-то не так. - person tchrist; 30.08.2011