В чем разница между кодированием / декодированием?

180

Я никогда не был уверен, что понимаю разницу между декодированием str / unicode и кодированием.

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

Я знаю, что unicode().encode()преобразует символы Unicode в строку байтов в соответствии с заданным именем кодировки.

Но я не понимаю, для чего str().encode()и unicode().decode()для чего. Может ли кто-нибудь объяснить, а возможно и исправить что-то еще, что я ошибся выше?

РЕДАКТИРОВАТЬ:

Несколько ответов дают информацию о том, что .encodeделает на строке, но никто, кажется, не знает, что .decodeделает для Unicode.

ʞɔıu
источник
Я думаю, что второй ответ на этой странице достаточно ясен и лаконичен.
Бен

Ответы:

106

decodeМетод Юникода строк действительно не имеет каких - либо приложений на всех (если у вас есть какие - то не-текстовые данные в юникод строку для какой - то причине - см . Ниже) Я думаю, что в основном это происходит по историческим причинам. В Python 3 это полностью исчезло.

unicode().decode()будет выполнять неявное кодирование с sиспользованием кодека по умолчанию (ascii). Проверьте это так:

>>> s = u'ö'
>>> s.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

>>> s.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

Сообщения об ошибках точно такие же.

Для str().encode()это наоборот - она пытается неявное декодирование в sс кодировкой по умолчанию:

>>> s = 'ö'
>>> s.decode('utf-8')
u'\xf6'
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

Используется вот так, str().encode()тоже лишнее.

Но есть другое применение последнего метода, который полезен: есть кодировки , которые не имеют ничего общего с наборами символов и, таким образом, могут быть применены к 8-битным строкам осмысленным способом:

>>> s.encode('zip')
'x\x9c;\xbc\r\x00\x02>\x01z'

Вы правы, хотя: неоднозначное использование «кодирования» для обоих этих приложений ... удивительно. Опять же, с отдельными byteи stringтипами в Python 3, это больше не проблема.


источник
4
.decode()на строки Юникода могут быть полезны, например,print u'\\u0203'.decode('unicode-escape')
JFS
Хороший пример @JFSebastian в python3 Я думаю, вы бы сделали:print u'\\u0203'.encode('utf8').decode('unicode-escape')
AJP
1
@AJP: на Python 3:codecs.decode(u'\\u0203', 'unicode-escape')
JFS
@hop: да. Чтобы обнаружить неверный ввод и для совместимости с Python 2/3, строка может быть явно закодирована с использованием asciiкодировки:\\u0203\u00e4'.encode('ascii').decode('unicode-escape')
jfs
@hop: ваш первый комментарий (почему вы удалили его? Не удаляйте комментарии, на которые были даны ответы) уже сказал это. Мой ответ ( .encode('ascii').decode('unicode-escape')) не зависит от sys.getdefaultencoding().
Jfs
71

Представление строки Юникода в виде строки байтов называется кодированием . Использование u'...'.encode(encoding).

Пример:

    >>> u'æøå'.encode ('utf8')
    '\ Xc3 \ x83 \ xc2 \ xa6 \ xc3 \ x83 \ xc2 \ XB8 \ xc3 \ x83 \ xc2 \ xa5'
    >>> u'æøå'.encode ('latin1')
    '\ Xc3 \ xa6 \ xc3 \ XB8 \ xc3 \ xa5'
    >>> u'æøå'.encode ('ascii')
    UnicodeEncodeError: кодек «ascii» не может кодировать символы в позиции 0-5: 
    порядковый номер вне диапазона (128)

Вы обычно кодируете строку Unicode всякий раз, когда вам нужно использовать ее для ввода-вывода, например, передавать ее по сети или сохранять в файл на диске.

Преобразование строки байтов в строку Unicode называется декодированием . Используйте unicode('...', encoding)или '...'. Decode (кодировка).

Пример:

   >>> Вы
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5' # интерпретатор печатает объект Unicode следующим образом
   >>> Юникод ('\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5', 'latin1')
   и '\ xc3 \ xa6 \ xc3 \ XB8 \ xc3 \ xa5'
   >>> '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'.decode (' latin1 ')
   и '\ xc3 \ xa6 \ xc3 \ XB8 \ xc3 \ xa5'

Обычно вы декодируете строку байтов всякий раз, когда вы получаете строковые данные из сети или из файла на диске.

Я полагаю, что в Python 3 есть некоторые изменения в обработке Unicode, поэтому вышеприведенное, вероятно, не правильно для Python 3.

Несколько хороших ссылок:

codeape
источник
6
Вы не ответили на вопрос ОП. ОП хочет знать, что делают str.encode () и unicode.decode (). Вы только что повторили то, что было сказано в исходном вопросе.
Stuckintheshuck
Отличный ответ, почему на практике вы когда-нибудь связывались с декодированием и кодированием. Не каждая машина понимает один и тот же набор символов, но все они понимают байты. Кодирование в байты для языка, который универсальные компьютеры понимают (и может быть перенесено или сохранено на диск), но декодируется, когда люди действительно должны прочитать эти байты (например, на стороне клиента).
Алекс Петралия
Фантастический ответ! Это должно идти вверх!
sandyp
16

anUnicode. кодирование ('кодирование') приводит к строковому объекту и может быть вызвано для объекта Unicode

строка. decode ('encoding') приводит к объекту Unicode и может быть вызван на строку, закодированную в данной кодировке.


Еще несколько объяснений:

Вы можете создать некоторый объект Unicode, который не имеет никакой установленной кодировки. То, как он хранится в памяти Python, не имеет значения. Вы можете искать его, разбивать его и вызывать любую функцию управления строками, которая вам нравится.

Но наступает момент, когда вы хотите распечатать объект Unicode на консоли или в каком-либо текстовом файле. Таким образом, вы должны закодировать его (например, в UTF-8), вы вызываете кодирование ('utf-8'), и вы получаете строку с '\ u <someNumber>' внутри, которая отлично печатается.

Затем, опять же - вы хотели бы сделать обратное - прочитать строку, закодированную в UTF-8, и обработать ее как Unicode, чтобы \ u360 был одним символом, а не 5. Затем вы декодируете строку (с выбранной кодировкой) и получить новый объект типа Unicode.

Как примечание - вы можете выбрать некоторую извращенную кодировку, такую ​​как 'zip', 'base64', 'rot', и некоторые из них будут конвертировать из строки в строку, но я считаю, что наиболее распространенным случаем является случай UTF-8 / UTF-16 и строка.

Abgan
источник
12

mybytestring.encode (somecodec) имеет смысл для следующих значений somecodec:

  • base64
  • BZ2
  • Zlib
  • наговор
  • quopri
  • rot13
  • string_escape
  • уу

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

nosklo
источник
5

Существует несколько кодировок, которые можно использовать для дешифрования / кодирования из str в str или из unicode в unicode. Например, base64, hex или даже rot13. Они перечислены в модуле кодеков .

Редактировать:

Сообщение декодирования в строке Unicode может отменить соответствующую операцию кодирования:

In [1]: u'0a'.decode('hex')
Out[1]: '\n'

Возвращаемый тип str вместо unicode, что на мой взгляд неудачно. Но если вы не выполняете правильное кодирование / декодирование между str и unicode, это все равно выглядит как беспорядок.


источник
1
-1: метод декодирования не применяется к объекту Unicode. Вместо этого объект unicode кодируется как строка байтов 'ascii', прежде чем начнется операция декодирования. Для доказательства этого утверждения попробуйте u'ã'.decode ('hex') - который приводит к UnicodeEncodeError
nosklo
2
@nosklo: Вы правы. Что я действительно имел в виду, так это то, что у объектов Юникода есть метод decode (), так что вы также можете применять к ним кодировки не-кодировки символов. Весь этот бизнес, не связанный с кодировкой символов, делает этот интерфейс беспорядочным в Python <3
1

Простой ответ заключается в том, что они являются полной противоположностью друг другу.

Компьютер использует базовую единицу байта для хранения и обработки информации; это бессмысленно для человеческих глаз.

Например, '\ xe4 \ xb8 \ xad \ xe6 \ x96 \ x87' - это представление двух китайских символов, но компьютер знает (что означает печать или хранение), что это китайские иероглифы, когда им дают словарь для поиска этого Китайское слово, в данном случае это словарь «utf-8», и оно не сможет правильно отобразить намеченное китайское слово, если вы загляните в другой или неправильный словарь (используя другой метод декодирования).

В приведенном выше случае процесс поиска на компьютере китайского слова decode().

И процесс компьютерной записи китайцев в компьютерную память идет encode().

Таким образом, закодированная информация - это необработанные байты, а декодированная информация - это необработанные байты и имя словаря для ссылки (но не сам словарь).

Эрен Бэй
источник