Типы Python str и Unicode

Работая с Python 2.7, мне интересно, какое реальное преимущество в использовании типа unicode вместо str, поскольку оба они, похоже, могут хранить строки Unicode. Есть ли какая-то особая причина, кроме возможности устанавливать коды unicode строки unicode с помощью escape char \?:

Выполнение модуля с помощью:

# -*- coding: utf-8 -*-

a = 'á'
ua = u'á'
print a, ua

Результаты в: á, á

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

Больше тестирования с использованием оболочки Python:

>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'

Итак, строка unicode, по-видимому, кодируется с использованием latin1 вместо utf-8 а необработанная строка кодируется с помощью utf-8? Я еще больше смущен! : S

Ответ 1

unicode предназначен для обработки текста. Текст представляет собой последовательность кодовых точек, которая может быть больше одного байта. Текст может быть закодирован в определенной кодировке для представления текста в виде необработанных байтов (например, utf-8, latin-1...).

Обратите внимание, что unicode не закодировано! Внутреннее представление, используемое python, представляет собой деталь реализации, и вы не должны заботиться об этом, пока он может представлять нужные вам кодовые точки.

Наоборот, str в Python 2 - простая последовательность байтов. Он не представляет текст!

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

Примечание. В Python 3, unicode был переименован в str и появился новый тип bytes для простой последовательности байтов.

Некоторые отличия, которые вы можете видеть:

>>> len(u'à')  # a single code point
1
>>> len('à')   # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte
�

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

>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
à�ìòù

Что раньше было верно UTF-8, больше нет. Используя строку unicode, вы не можете работать так, чтобы результирующая строка недействительна в тексте unicode. Вы можете удалить кодовую точку, заменить кодовую точку другой кодовой точкой и т.д., Но вы не можете возиться с внутренним представлением.

Ответ 2

Ваш терминал, как правило, настроен на UTF-8.

Тот факт, что печать a работает, является совпадением; вы пишете необработанные байты UTF-8 на терминал. a - это значение длины два, содержащее два байта, шестнадцатеричные значения C3 и A1, тогда как ua - значение юникода длиной одна, содержащее кодовую точку U + 00E1.

Это различие в длине является одной из основных причин использования значений Unicode; вы не можете легко измерить количество текстовых символов в байтовой строке; строка len() байтовой строки сообщает вам, сколько байтов использовалось, а не количество символов, которые были закодированы.

Вы можете видеть разницу, когда вы кодируете значение unicode для разных выходных кодировок:

>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'

Обратите внимание, что первые 256 кодовых точек стандарта Unicode соответствуют стандарту Latin 1, поэтому код U + 00E1 кодируется на латиницу 1 в виде байта с шестнадцатеричным значением E1.

Кроме того, Python использует escape-коды в представлениях строк unicode и байтов, а нижние кодовые точки, которые не подлежат печати ASCII, представлены с использованием значений \x.. escape. Вот почему строка Unicode с кодовой точкой между 128 и 255 выглядит так же, как кодировка Latin 1. Если у вас есть строка unicode с кодовыми точками за пределами U + 00FF, другая escape-последовательность используется вместо \u.... с шестизначным шестнадцатеричным значением.

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

Ответ 3

Юникод и кодировки - совершенно разные, несвязанные вещи.

Unicode

Назначает числовой идентификатор для каждого символа:

  • 0x41 → A
  • 0xE1 → á
  • 0x414 → Д

Итак, Unicode назначает число 0x41 на A, 0xE1 на á и 0x414 на Д.

Даже маленькая стрелка → я использовал ее номер Юникода, это 0x2192. И даже emojis имеют свои номера Unicode, 😂 равно 0x1F602.

Вы можете найти номера Юникода всех символов в этой таблице. В частности, вы можете найти первые три символа выше здесь, стрелку здесь, и смайлик здесь.

Эти номера, присвоенные всем символам Unicode, называются кодовыми точками.

Цель всего этого состоит в том, чтобы обеспечить возможность однозначного обращения к каждому персонажу. Например, если я говорю о 😂, вместо того, чтобы сказать "вы знаете, этот смеющийся эмози со слезами", я могу сказать, что код кода Unicode 0x1F602. Легче, правда?

Обратите внимание, что кодовые точки Unicode обычно форматируются с помощью ведущего U+, а затем шестнадцатеричное числовое значение, заполненное как минимум 4 цифрами. Таким образом, приведенными выше примерами будут U+ 0041, U+ 00E1, U+ 0414, U+ 2192, U+ 1F602.

Кодовые точки Юникода варьируются от U+ 0000 до U+ 10FFFF. Это 1114112 номеров. 2048 из этих чисел используются для суррогатов, таким образом, остается 1112 064. Это означает, что Unicode может назначить уникальный идентификатор (кодовую точку) до 1,112,064 различных символов. Не все эти кодовые точки назначаются символу, но Unicode постоянно расширяется (например, при введении новых emojis).

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

Кодировки

Отображать символы в битовые шаблоны.

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

Существует множество различных кодировок, которые охватывают разные подмножества символов. В англоязычном мире наиболее распространенными кодировками являются:

ASCII

Карты 128 символов (кодовые точки U+ 0000 до U+ 007F) для битовых паттернов длины 7.

Пример:

  • a → 1100001 (0x61)

Вы можете увидеть все сопоставления в этой таблице.

ISO 8859-1 (aka Latin-1)

Отображает 191 символ (коды U+ 0020 на U+ 007E и U+ 00A0 на U+ 00FF) на битовые рисунки длиной 8.

Пример:

  • a → 01100001 (0x61)
  • á → 11100001 (0xE1)

Вы можете увидеть все сопоставления в этой таблице.

UTF-8,

Карты 1,112,064 символов (все существующие кодовые точки Юникода) для битовых шаблонов длиной 8, 16, 24 или 32 бита (то есть 1, 2, 3 или 4 байта).

Пример:

  • a → 01100001 (0x61)
  • á → 11000011 10100001 (0xC3 0xA1)
  • ≠ → 11100010 10001001 10100000 (0xE2 0x89 0xA0)
  • 😂 → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)

То, как UTF-8 кодирует символы в битовые строки, очень хорошо описано здесь.

Юникод и кодировки

Рассматривая приведенные выше примеры, становится ясно, как Unicode полезен.

Например, если я латинский-1, и я хочу объяснить свою кодировку, мне не нужно говорить:

"Я кодирую, что a с aigu (или, тем не менее, вы называете это растущим баром) как 11100001"

Но я могу просто сказать:

"Я кодирую U+ 00E1 как 11100001"

И если я UTF-8, могу сказать:

"Я, в свою очередь, кодирую U+ 00E1 как 11000011 10100001"

И это однозначно ясно для всех, кого мы имеем в виду.

Теперь к часто возникающей путанице

Верно, что иногда битовая схема кодирования, если вы интерпретируете ее как двоичное число, такая же, как и кодовая точка Юникода этого символа.

Например:

  • ASCII кодирует как 1100001, который вы можете интерпретировать как шестнадцатеричное число 0x61, а кодовая точка Unicode - U+ 0061.
  • Latin-1 кодирует как 11100001, который вы можете интерпретировать как шестнадцатеричное число 0xE1, а кодовая точка Unicode для [a] - U+ 00E1.

Разумеется, это было сделано специально для удобства. Но вы должны смотреть на это как на чистое совпадение. Битовая диаграмма, используемая для представления символа в памяти, никак не связана с кодовой точкой Юникода этого символа.

Никто даже не говорит, что вам нужно интерпретировать битовую строку, такую как 11100001, как двоичное число. Просто посмотрите на это как последовательность бит, которую использует Latin-1 для кодирования символа.

Вернуться к вашему вопросу

Кодировка, используемая вашим интерпретатором Python, - UTF-8.

Вот что происходит в ваших примерах:

Пример 1

Следующее кодирует символ U в UTF-8. Это приводит к битовой строке 11000011 10100001, которая сохраняется в переменной a.

>>> a = 'á'

Когда вы смотрите на значение a, его содержимое 11000011 10100001 форматируется как шестнадцатеричный номер 0xC3 0xA1 и выводится как '\xc3\xa1':

>>> a
'\xc3\xa1'

Пример 2.

Ниже сохранена кодовая точка Юникода á, которая является U+ 00E1, в переменной ua (мы не знаем, какой формат данных Python использует внутри, чтобы представить кодовую точку U+ 00E1 в памяти, и это не важно для нас ):

>>> ua = u'á'

Когда вы смотрите на значение ua, Python сообщает вам, что он содержит кодовую точку U+ 00E1:

>>> ua
u'\xe1'

Пример 3.

Следующее кодирует кодовую точку Unicode U+ 00E1 (представляющую символ á) с UTF-8, что приводит к битовой схеме 11000011 10100001. Опять же, для вывода этот бит-шаблон представляется шестнадцатеричным числом 0xC3 0xA1:

>>> ua.encode('utf-8')
'\xc3\xa1'

Пример 4.

Следующее кодирует кодовую точку Юникода U+ 00E1 (представляющую символ á) с латиницей-1, что приводит к битовой схеме 11100001. Для вывода эта битовая диаграмма представляется как шестнадцатеричный номер 0xE1, который по совпадению совпадает с начальная кодовая точка U+ 00E1:

>>> ua.encode('latin1')
'\xe1'

Нет никакой связи между объектом Unicode ua и кодировкой Latin-1. То, что кодовая точка á является U+ 00E1, а кодировка Latin-1 á равна 0xE1 (если вы интерпретируете битовую структуру кодировки как двоичное число) является чистым совпадением.

Ответ 4

Когда вы определяете a как unicode, символы a и á равны. В противном случае á считается двумя символами. Попробуйте len (a) и len (au). В дополнение к этому, возможно, потребуется кодирование при работе с другими средами. Например, если вы используете md5, вы получаете разные значения для a и ua