Python UnicodeDecodeError - Неправильно ли я понимаю кодировку?
Проблема с кодировкой в Python
У меня возникла проблема с кодировкой строки в Python. Я пытался добавить строку 'add \x93Monitoring\x93 to list'
в список, используя метод encode
с параметром 'latin-1'
и ignore
, но это приводит к ошибке. Я ожидал, что параметр 'ignore'
должен был помочь игнорировать недопустимые символы. Вот код, который вызывает ошибку:
>>> '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)
Не могли бы вы подсказать, почему это происходит и как правильно обработать данную ситуацию?
2 ответ(ов)
Здесь есть причина, по которой их называют "кодировками"...
Немного вводной информации: думайте о юникоде как о норме или идеальном состоянии. Юникод — это просто таблица символов. №65 — это латинская заглавная буква A. №937 — греческая заглавная омега. И только это.
Чтобы компьютер мог хранить и/или обрабатывать юникод, он должен закодировать его в байты. Самая простая кодировка юникода — UCS-4; каждый символ занимает 4 байта, и доступны все ~1000000 символов. Эти 4 байта содержат номер символа в таблицах юникода как 4-байтовое целое число. Еще одна очень полезная кодировка — UTF-8, которая может кодировать любой символ юникода с помощью одного до четырех байтов. Но также есть и некоторые ограниченные кодировки, такие как "latin1", которые включают очень ограниченный диапазон символов, в основном используемых западными странами. Такие кодировки используют всего один байт на символ.
По сути, юникод может быть закодирован с помощью множества кодировок, и закодированные строки могут быть декодированы обратно в юникод. Дело в том, что юникод появился довольно поздно, так что все мы, кто вырос на 8-битных символьных наборах, узнали слишком поздно, что всё это время мы работали с закодированными строками. Кодировка могла быть ISO8859-1, или windows CP437, или CP850 и т.д., в зависимости от вашей системной кодовой страницы по умолчанию.
Таким образом, когда в вашем исходном коде вы вводите строку "add “Monitoring“ to list" (и, думаю, вы имели в виду строку "add “Monitoring” to list", обратите внимание на вторую кавычку), вы на самом деле используете строку, уже закодированную в соответствии с кодовой страницей по умолчанию вашей системы (по байту \x93 я предполагаю, что вы используете кодировку Windows 1252 — “Западная”). Если вы хотите получить юникод из этого, вам нужно декодировать строку из кодировки "cp1252".
Таким образом, что вы на самом деле хотели сделать, это:
"add \x93Monitoring\x94 to list".decode("cp1252", "ignore")
К сожалению, в Python 2.x есть и метод .encode
для строк; это удобная функция для "специальных" кодировок, таких как "zip", "rot13" или "base64", которые не имеют отношения к юникоду.
В любом случае, все, что вам нужно запомнить для ваших преобразований между юникодом и байтами, это:
- юникодная строка кодируется в строку Python 2.x (на самом деле — в последовательность байтов)
- строка Python 2.x декодируется в юникодную строку
В обоих случаях вам необходимо указать кодировку, которая будет использоваться.
Я не очень ясен, я устал, но надеюсь, что смог помочь.
P.S. Юмористическая на заметка: у маяков не было юникода; у древних римлян, древних греков и древних египтян тоже не было. У всех этих цивилизаций были свои "кодировки", и они довольно пренебрегали другими культурами. Все эти цивилизации развалились в прах. Подумайте об этом, люди! Сделайте свои приложения осведомленными о юникоде, ради блага человечества. 😃
P.S.2 Пожалуйста, не портьте предыдущий пост, говоря "Но китайцы...". Если вам нужно это сделать или вы чувствуете, что обязаны, отложите это, подумав, что базовая многобайтовая кодировка Unicode (BMP) в основном состоит из китайских иероглифов, следовательно, китайский является основой юникода. Я могу продолжать выдумывать абсурдные лжи, лишь бы люди разрабатывали приложения, учитывающие юникод.
В вашем примере строка, которую вы используете, действительно является строкой Unicode, так как она начинается с u'...'
. Это означает, что функция encode
доступна для этой строки. Однако, символы, которые вы используете (например, \x93
), могут не поддерживаться в вашей текущей кодировке.
Попробуйте использовать метод encode
с кодировкой latin-1
, чтобы увидеть, как это работает. В вашем коде вы правильно указали ignore
, что позволяет игнорировать неподдерживаемые символы.
Вот ваш пример:
>>> u'add \x93Monitoring\x93 to list '.encode('latin-1', 'ignore')
'add \x93Monitoring\x93 to list '
Обратите внимание, что \x93
— это обозначение символа, который может быть не поддержан в кодировке latin-1
. Если вы хотите, чтобы он был корректно закодирован, убедитесь, что используете правильную кодировку, например, utf-8
, когда это возможно.
Если у вас есть дополнительные вопросы или нужна помощь с кодировкой, дайте знать!
UnicodeEncodeError: 'ascii' кодек не может закодировать символ u'\xa0' на позиции 20: номер не в диапазоне (128)
UnicodeDecodeError: Кодек 'charmap' не может декодировать байт X в позиции Y: символ отображается как <неопределённый>
Как лучше всего удалить акценты (нормализовать) в строке Unicode Python?
Python DictWriter: Запись UTF-8 закодированных CSV файлов
Как получить не-ASCII URL с помощью urlopen?