Поиск по сайту:

Как работать с Unicode в Python


Автор выбрал программу Write for DOnations.

Введение

Юникод — это стандартная кодировка символов для большинства компьютеров в мире. Это гарантирует, что текст, включая буквы, символы, эмодзи и даже управляющие символы, будет выглядеть одинаково на разных устройствах, платформах и цифровых документах, независимо от используемой операционной системы или программного обеспечения. Это важная часть Интернета и компьютерной индустрии, и без нее Интернет был бы гораздо более хаотичным и сложным в использовании.

Юникод сам по себе не является кодировкой, а больше похож на базу данных почти всех возможных символов на земле. Unicode содержит кодовую точку, идентификатор для каждого символа в своей базе данных, который может иметь значение от 0 до 1,1 миллиона, а это означает, что маловероятно, что в ближайшее время у него закончатся эти уникальные кодовые точки. Каждая кодовая точка в Unicode представлена как U+n, где U+ означает, что это кодовая точка Unicode, а n — это набор из четырех до шести шестнадцатеричных цифр для символа. Это гораздо более надежная система кодирования, чем ASCII, которая представляет только 128 символов. Обмен цифровым текстом по всему миру с помощью ASCII был затруднен, потому что он основан на американском английском и не поддерживает символы с диакритическими знаками. Unicode, с другой стороны, содержит почти 150 000 символов и охватывает символы всех языков мира.

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

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

Предпосылки

Чтобы следовать этому руководству, вам понадобятся:

  • Python установлен локально или на удаленном сервере. Если у вас еще не установлен Python, вы можете сделать это, следуя нашему руководству «Как установить Python 3 и настроить среду программирования». Выберите версию, подходящую для вашего дистрибутива Linux.
  • Знакомство с основами программирования Python и строковыми методами Python
  • Знание того, как работать с интерактивной консолью Python.

Шаг 1 — Преобразование кодовых точек Unicode в Python

Кодирование — это процесс представления данных в машиночитаемой форме. Существует множество способов кодирования данных — ASCII, Latin-1 и другие, и каждая кодировка имеет свои сильные и слабые стороны, но, пожалуй, наиболее распространенной является UTF-8. Это тип кодирования, который позволяет отображать символы со всего мира в одном наборе символов. Таким образом, UTF-8 является важным инструментом для всех, кто работает с интернационализированными данными. В общем, UTF-8 — хороший выбор для большинства целей. Он относительно эффективен и может использоваться с различным программным обеспечением. UTF-8 берет кодовую точку Unicode и преобразует ее в шестнадцатеричные байты, понятные компьютеру. Другими словами, Unicode — это сопоставление, а UTF-8 позволяет компьютеру понять это сопоставление.

В Python 3 кодировкой строки по умолчанию является UTF-8, что означает, что любая кодовая точка Unicode в строке Python автоматически преобразуется в соответствующий символ.

На этом шаге вы создадите символ авторского права (©), используя его кодовую точку Unicode в Python. Сначала запустите интерактивную консоль Python в своем терминале и введите следующее:

>>> s =  '\u00A9'
>>> s

В предыдущем коде вы создали строку s с кодовой точкой Unicode \u00A9. Как упоминалось ранее, поскольку строка Python по умолчанию использует кодировку UTF-8, печать значения s автоматически заменяет его на соответствующий символ Unicode. Обратите внимание, что \u в начале кода обязателен. Без него Python не сможет преобразовать кодовую точку. Вывод предыдущего кода возвращает соответствующий символ Unicode:

Output
'©'

Язык программирования Python предоставляет встроенные функции для кодирования и декодирования строк. Функция encode() преобразует строку в строку байтов.

Чтобы продемонстрировать это, откройте интерактивную консоль Python и введите следующий код:

>>> '🅥'.encode('utf-8')

Это создает строку байтов символа в качестве вывода:

Output
b'\xf0\x9f\x85\xa5'

Обратите внимание, что перед каждым байтом стоит \x, что указывает на то, что это шестнадцатеричное число.

Примечание. Ввод специальных символов Юникода в Windows и на Mac отличается. В предыдущем коде и во всем коде в этом руководстве, где используются символы, вы можете вставлять символы с помощью служебной программы «Карта символов» в Windows. У Mac нет этой функции, поэтому лучше всего скопировать символ из примеров кода.

Затем вы будете использовать функцию decode() для преобразования строки байтов обратно в строку. Функция decode() принимает тип кодировки в качестве аргумента. Также стоит отметить, что функция decode() может декодировать только строку байтов, которая указывается буквой b в начале строки. Удаление b приведет к ошибке AttributeError.

В консоли введите:

>>> b'\xf0\x9f\x85\xa5'.decode('utf-8')

Код вернет вывод следующим образом:

Output
'🅥'

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

Шаг 2 — Нормализация Unicode в Python

На этом шаге вы нормализуете Unicode в Python. Нормализация помогает определить, являются ли два символа, написанные разными шрифтами, одинаковыми, что полезно, когда два символа с разными кодовыми точками дают одинаковый результат. Например, символы Unicode R и для человеческого глаза одинаковы, так как они оба представляют собой букву R, но компьютер считает чтобы они были разными персонажами.

Следующий пример кода дополнительно демонстрирует это. Откройте консоль Python и введите следующее:

>>> styled_R = 'ℜ'
>>> normal_R = 'R'
>>> styled_R == normal_R

Вы получите следующий вывод:

Output
False

Код выводит False в качестве вывода, потому что строки Python не считают эти два символа идентичными. Именно благодаря этой способности различать нормализация важна при работе с Unicode.

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

>>> s1 =  'hôtel'
>>> s2 = 'ho\u0302tel'
>>> len(s1), len(s2)

В предыдущем коде вы создали строку s1, содержащую символ ô, а во второй строке строка s2 содержит кодовую точку символ циркумфлекса ( ̂ ). После выполнения код возвращает следующий вывод:

Output
(5, 6)

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

>>> s1 == s2

Код возвращает следующий вывод:

Output
False

Хотя строковые переменные s1 и s2 создают один и тот же символ Unicode, они различаются по длине и, следовательно, не равны.

Вы можете решить эту проблему с помощью функции normalize(), что вы и сделаете на следующем шаге.

Шаг 3 — Нормализация Unicode с помощью NFD, NFC, NFKD и NFKC

На этом шаге вы нормализуете строки Unicode с помощью функции normalize() из библиотеки unicodedata Python в модуле unicodedata, который обеспечивает возможности поиска и нормализации символов. Функция normalize() может принимать форму нормализации в качестве первого аргумента и нормализуемую строку в качестве второго аргумента. В Unicode есть четыре типа форм нормализации, которые вы можете использовать для этого: NFD, NFC, NFKD и NFKC.

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

Откройте консоль и введите следующее:

>>> from unicodedata import normalize
>>> s1 =  'hôtel'
>>> s2 = 'ho\u0302tel'
>>> s1_nfd = normalize('NFD', s1)
>>> len(s1), len(s1_nfd)

Код производит следующий вывод:

Output
(5, 6)

Как показывает пример, нормализация строки s1 увеличивает ее длину на один символ. Это связано с тем, что символ ô разделяется на два символа, o и ˆ, что вы можете подтвердить, используя следующий код:

>>> s1.encode(), s1_nfd.encode()

Полученный вывод показывает, что после кодирования нормализованной строки символ o отделился от символа ˆ в строке s1_nfd:

Output
(b'h\xc3\xb4tel', b'ho\xcc\x82tel')

Форма нормализации NFC сначала разлагает символ, а затем повторно компонует его с любым доступным комбинирующим символом. Поскольку NFC составляет строку для получения кратчайшего результата, W3C рекомендует использовать NFC в Интернете. Ввод с клавиатуры по умолчанию возвращает составленные строки, поэтому в этом случае рекомендуется использовать NFC.

Например, введите в интерактивную консоль следующее:

>>> from unicodedata import normalize
>>> s2_nfc = normalize('NFC', s2)
>>> len(s2), len(s2_nfc)

Код производит следующий вывод:

Output
(6, 5)

В примере нормализация строки s2 уменьшает ее длину на единицу. Вы можете убедиться в этом, запустив следующий код в интерактивной консоли:

>>> s2.encode(), s2_nfc.encode()

Вывод кода:

Output
(b'ho\xcc\x82tel', b'h\xc3\xb4tel')

Вывод показывает, что символы o и ˆ объединены в один символ ô.

Формы нормализации NFKD и NFKC используются для «строгой» нормализации и могут использоваться для решения множества задач, связанных с поиском и сопоставлением с образцом в строках Unicode. «K» в NFKD и NFKC означает совместимость.

Формы нормализации NFD и NFC разлагают символы, но NFKD и NFKC выполняют разложение совместимости для символов, которые не похожи, но эквивалентны, удаляя любые различия форматирования. Например, строка ②① не похожа на 21, но обе они представляют одно и то же значение. Формы нормализации NFKC и NFKD удаляют это форматирование (в данном случае круг вокруг цифр) из символов, чтобы обеспечить их наиболее упрощенную форму.

Следующий пример демонстрирует разницу между формами нормализации NFD и NFKD. Откройте интерактивную консоль Python и введите следующее:

>>> s1 = '2⁵ô'
>>> from unicodedata import normalize
>>> normalize('NFD', s1), normalize('NFKD', s1)

Вы получите следующий вывод:

Output
('2⁵ô', '25ô')

Вывод показывает, что форма NFD не может разложить символ экспоненты в строке s1, но NFKD вырезает форматирование экспоненты и заменяет символ совместимости (в данном случае экспоненту 5) с его эквивалентом (5 как цифра). Помните, что формы нормализации NFD и NFKD все еще разлагают символы, поэтому символ ô должен увеличить свою длину на единицу, как вы видели в предыдущем примере NFD. Вы можете подтвердить это, выполнив следующий код:

>>> len(normalize('NFD', s1)), len(normalize('NFKD', s1))

Код вернет следующее:

Output
(4, 4)

Форма нормализации NFKC работает аналогичным образом, но создает символы, а не разлагает их. В той же консоли Python введите следующее:

>>> normalize('NFC', s1), normalize('NFKC', s1)

Код возвращает следующее:

Output
('2⁵ô', '25ô')

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

>>> len(normalize('NFC', s1)), len(normalize('NFKC', s1))

Это вернет следующий вывод:

Output
(3, 3)

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

Шаг 4 — Решение ошибок Unicode в Python

При обработке Unicode в Python могут возникать два типа ошибок Unicode: UnicodeEncodeError и UnicodeDecodeError. Хотя эти ошибки Unicode могут сбивать с толку, ими можно управлять, и вы исправите обе эти ошибки на этом шаге.

Решение ошибки UnicodeEncodeError

Кодирование в Unicode — это процесс преобразования строки Unicode в байты с использованием определенной кодировки. Ошибка UnicodeEncodeError возникает при попытке закодировать строку, содержащую символы, которые не могут быть представлены в указанной кодировке.

Чтобы создать эту ошибку, вы будете кодировать строку, содержащую символы, не входящие в набор символов ASCII.

Откройте консоль и введите следующее:

>>> ascii_supported = '\u0041'
>>> ascii_supported.encode('ascii')

Ниже приведен ваш вывод:

Output
b'A'

Затем введите следующее:

>>> ascii_unsupported = '\ufb06'
>>> ascii_unsupported.encode('utf-8')

Вы получите следующий результат:

Output
b'\xef\xac\x86'

Наконец, введите следующее:

>>> ascii_unsupported.encode('ascii')

Однако при запуске этого кода вы получите следующую ошибку:

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

ASCII имеет ограниченное количество символов, и Python выдает ошибки, когда находит символ, которого нет в кодировке ASCII. Поскольку кодировка ASCII не распознает кодовую точку \ufb06, Python возвращает сообщение об ошибке, в котором говорится, что ASCII имеет диапазон только 128 и соответствующий десятичный эквивалент этой кодовой точки не находится в этом диапазоне.

Вы можете обработать UnicodeEncodeError, используя аргумент errors в функции encode(). Аргумент errors может иметь одно из трех значений: ignore, replace и xmlcharrefreplace.

Откройте консоль и введите следующее:

>>> ascii_unsupported = '\ufb06'
>>> ascii_unsupported.encode('ascii', errors='ignore')

Вы получите следующий вывод

Output
b''

Далее введите следующее:

>>> >>> ascii_unsupported.encode('ascii', errors='replace')

Вывод будет:

Output
b'?'

Наконец, введите следующее:

>>> ascii_unsupported.encode('ascii', errors='xmlcharrefreplace')

Результат:

Output
b'&#64262;'

В каждом случае Python не выдает ошибку.

Как показано в предыдущем примере, ignore пропускает символ, который не может быть закодирован, replace заменяет символ на ?, а xmlcharrefreplace заменяет некодируемые символы сущностью XML.

Решение ошибки UnicodeDecodeError

UnicodeDecodeError возникает при попытке декодировать строку, содержащую символы, которые не могут быть представлены в указанной кодировке.

Чтобы создать эту ошибку, вы попытаетесь декодировать строку байтов в кодировку, которую невозможно декодировать.

Откройте консоль и введите следующее:

>>> iso_supported = '§'
>>> b = iso_supported.encode('iso8859_1')
>>> b.decode('utf-8')

Вы получите следующую ошибку:

Output
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa7 in position 0: invalid start byte

Если вы столкнулись с этой ошибкой, вы можете использовать аргумент errors в функции decode(), что может помочь вам декодировать строку. Аргумент errors принимает два значения: ignore и replace.

Чтобы продемонстрировать это, откройте консоль Python и введите следующий код:

>>> iso_supported = '§A'
>>> b = iso_supported.encode('iso8859_1')
>>> b.decode('utf-8', errors='replace')

Ваш вывод будет:

Output
'�A'

Затем введите следующее:

>>> b.decode('utf-8', errors='ignore')

Ваш вывод будет:

Output
'A'

В предыдущем примере при использовании значения replace в функции decode() был добавлен символ , а при использовании ignore ничего не возвращал, когда декодер (в данном случае utf-8) не мог декодировать байты.

При декодировании любой строки обратите внимание, что вы не можете предположить, что это за кодировка. Чтобы расшифровать любую строку, вы должны знать, как она была закодирована.

Заключение

В этой статье были рассмотрены основы использования Unicode в Python. Вы кодировали и декодировали строки, нормализовали данные с помощью NFD, NFC, NFKD и NFKC и устраняли ошибки Unicode. Вы также использовали формы нормализации в сценариях, связанных с сортировкой и поиском. Эти методы помогут вам справиться с проблемами Unicode с помощью Python. В качестве следующего шага вы можете прочитать How To Code in Python 3.