Работа с Unicode в Python: от кода к символу и обратно
Работа с Unicode символами в Python
Основной способ работы с Unicode символами в Python заключается в использовании встроенных функций chr() и ord(), а также escape-последовательностей \u и \U. Эти инструменты позволяют преобразовывать числовые коды символов в сами символы и наоборот, а также задавать произвольные Unicode символы непосредственно в строковых литералах.
Функция ord() принимает один символ (строку длины 1) и возвращает его код Unicode (целое число). Функция chr() принимает целое число (код символа) и возвращает соответствующую строку из одного символа. Escape-последовательность \u используется для 16-битных кодов (4 шестнадцатеричных цифры), а \U для полных 32-битных кодов (8 цифр).
# Пример получения кода символа
code = ord('A') # 65
print(code)
# Пример получения символа по коду
symbol = chr(65) # 'A'
print(symbol)
# Использование escape-последовательностей в строке
star = '\u2605' # ★ (звезда)
print(star)
elephant = '\U0001F418' # ? (слон)
print(elephant)
Python bytes encoding (кодирование байтов в python)
65 A ★ ?
Encoding decoding python (кодирование и декодирование в python)
Типичные проблемы:
- Попытка передать в chr() значение за пределами диапазона 0–0x10FFFF (допустимые коды Unicode) вызовет исключение ValueError.
- Использование \u с кодом, который не соответствует ни одному символу (например, суррогатный блок 0xD800–0xDFFF), приведет к синтаксической ошибке или некорректному результату.
- В Python 3 все строки по умолчанию являются Unicode, поэтому не требуется дополнительных объявлений. Однако при работе с байтовыми строками могут возникать ошибки кодирования.
Для избежания ошибок следует проверять код на валидность с помощью 0x10FFFF и исключать диапазон суррогатов. В случае необходимости работы с эмодзи и символами вне BMP (Basic Multilingual Plane) следует использовать \U или суррогатные пары.
Как задать Unicode символ напрямую в коде, не используя chr()?
В Python 3 строки уже являются Unicode, поэтому символ можно вставить непосредственно, если редактор поддерживает кодировку UTF-8. Однако для переносимости кода часто используют escape-последовательности или именованные сущности модуля unicodedata.
# Прямое включение (если файл сохранен в UTF-8)
copyright_sign = '©'
print(copyright_sign)
# Именованная сущность через lookup
import unicodedata
sigma = unicodedata.lookup('GREEK SMALL LETTER SIGMA')
print(sigma)
Encoding python (кодировки в python)
© σ
Python 2 encoding (кодировки в python 2)
При прямом включении символов в исходный код может возникнуть путаница с кодировкой файла. Рекомендуется всегда сохранять файлы в UTF-8. Ошибка SyntaxError: Non-UTF-8 code starting with появляется, если файл сохранен в другой кодировке. Решение: указать кодировку в первой строке файла: # -*- coding: utf-8 -*- (актуально для Python 2, в Python 3 по умолчанию UTF-8).
Как получить имя Unicode символа и выполнить нормализацию строки?
Модуль unicodedata предоставляет функции name() и lookup(). name() возвращает официальное имя символа (или вызывает ValueError для символов без имени), а lookup() делает обратное. Функция normalize() приводит строку к одной из стандартных форм нормализации (NFC, NFD, NFKC, NFKD).
import unicodedata
# Получение имени символа
char = 'ñ'
print(unicodedata.name(char)) # LATIN SMALL LETTER N WITH TILDE
# Поиск символа по имени
char2 = unicodedata.lookup('WHITE SMILING FACE')
print(char2) # ☺
# Нормализация: составная форма (NFC) и разложенная (NFD)
text = 'café'
nfc = unicodedata.normalize('NFC', text)
nfd = unicodedata.normalize('NFD', text)
print(nfc, nfd) # café vs café
print(len(nfc), len(nfd)) # 4 и 5
Python encode (метод encode в python)
LATIN SMALL LETTER N WITH TILDE ☺ café café 4 5
Codecs encode python (модуль codecs.encode в python)
Разные формы нормализации приводят к разной длине строки, что может повлиять на сравнение. Например, 'é' может быть представлена как один символ U+00E9 или как последовательность 'e' + U+0301. При сравнении строк важно нормализовать их к одной форме. Также функция name() не работает для управляющих символов и некоторых суррогатов, вызывая исключение.
Как преобразовать Unicode строку в байты в определённой кодировке и обратно?
Для преобразования строки в байты используется метод encode(), для обратного - decode(). В качестве параметра передаётся название кодировки (например, 'utf-8', 'utf-16', 'cp1251').
text = 'Привет, мир!'
# Кодирование в UTF-8
bytes_utf8 = text.encode('utf-8')
print(bytes_utf8) # b'\xd0\x9f...'
# Декодирование обратно
decoded = bytes_utf8.decode('utf-8')
print(decoded) # 'Привет, мир!'
# Ошибка при неверной кодировке
try:
bytes_utf8.decode('ascii') # вызовет UnicodeDecodeError
except UnicodeDecodeError as e:
print('Ошибка:', e)
Python encoding cp1251 (кодировка cp1251 в python)
b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!' Привет, мир! Ошибка: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)
Python encoding utf (кодировка utf в python)
Ошибки UnicodeEncodeError и UnicodeDecodeError возникают при несоответствии кодировки. Решение: использовать параметр errors (например, 'ignore', 'replace', 'xmlcharrefreplace') для обработки неотображаемых символов. При работе с данными из внешних источников необходимо точно знать их кодировку или использовать библиотеку chardet для её определения.
Как найти в строке все символы определённой Unicode категории (буквы, цифры, пунктуация)?
Модуль unicodedata предоставляет функцию category(), возвращающую двухбуквенный код категории (например, 'Lu' для заглавных букв). Также можно использовать регулярные выражения с флагом re.UNICODE и классами \p{} через библиотеку regex.
import unicodedata
import re
text = 'Привет123!'
# Поиск всех букв (категория начинается с L)
letters = [c for c in text if unicodedata.category(c).startswith('L')]
print(letters) # ['П', 'р', 'и', 'в', 'е', 'т']
# Использование библиотеки regex (установить: pip install regex)
import regex # нестандартная библиотека
matches = regex.findall(r'\p{L}+', text)
print(matches) # ['Привет']
Unicode символ python (unicode символ в python)
['П', 'р', 'и', 'в', 'е', 'т'] ['Привет']
Стандартный модуль re не поддерживает \p{}, поэтому для расширенной работы с Unicode категориями необходимо устанавливать стороннюю библиотеку regex. Также функция unicodedata.category() возвращает категорию для одного символа; для больших строк лучше использовать генератор или filter().
Расширенные примеры работы с Unicode в Python
Пример 1: Создание и анализ эмодзи (суррогатные пары)
Эмодзи, такие как ? (фейерверк), могут находиться за пределами базовой плоскости Unicode и требуют двух 16-битных значений (суррогатную пару) при использовании кодировки UTF-16. В Python 3 строки внутренне хранятся в виде последовательности кодовых точек (возможно, с использованием суррогатных пар для символов за пределами BMP), но при работе с len() возвращается количество символов Unicode, а не количество суррогатных пар.
# Эмодзи '?' (U+1F389)
em = '?'
print('Символ:', em)
print('Длина строки:', len(em)) # 1 (одна кодовая точка)
print('Код символа:', hex(ord(em))) # 0x1f389
# Прямое создание через escape
em2 = '\U0001F389'
print('Из эскейпа:', em2)
# Проверка на эмодзи с помощью категории
import unicodedata
print('Категория:', unicodedata.category(em)) # 'So' (Symbol Other)
# Ошибка: попытка записать эмодзи через \u (только 4 цифры)
# \u1F389 вызовет SyntaxError, поэтому используем \U
Символ: ? Длина строки: 1 Код символа: 0x1f389 Из эскейпа: ? Категория: So
Пример 2: Обработка ошибок кодирования (параметр errors)
При кодировании строки в кодировку, которая не может представить все символы, возникает исключение. Параметр errors позволяет управлять поведением: 'ignore' пропускает недопустимые символы, 'replace' заменяет их на '?', 'xmlcharrefreplace' заменяет на XML-сущность, 'backslashreplace' использует escape-последовательности.
text = 'Символ © и €'
# Кодирование в ASCII с обработкой ошибок
ascii_ignore = text.encode('ascii', errors='ignore')
print('ignore:', ascii_ignore)
ascii_replace = text.encode('ascii', errors='replace')
print('replace:', ascii_replace)
ascii_xml = text.encode('ascii', errors='xmlcharrefreplace')
print('xmlcharrefreplace:', ascii_xml)
ascii_backslash = text.encode('ascii', errors='backslashreplace')
print('backslashreplace:', ascii_backslash)
ignore: b'\xd0\xa1\xd0\xb8\xd0\xbc\xd0\xb2\xd0\xbe\xd0\xbb \xd0\xb8 ' replace: b'\xd0\xa1\xd0\xb8\xd0\xbc\xd0\xb2\xd0\xbe\xd0\xbb ? ?' xmlcharrefreplace: b'\xd0\xa1\xd0\xb8\xd0\xbc\xd0\xb2\xd0\xbe\xd0\xbb © €' backslashreplace: b'\xd0\xa1\xd0\xb8\xd0\xbc\xd0\xb2\xd0\xbe\xd0\xbb \\xa9 \\u20ac'
Пример 3: Нормализация и сравнение строк с акцентами
Строки могут быть визуально идентичны, но иметь разные формы нормализации. Функция unicodedata.normalize() помогает привести их к единой форме для сравнения.
import unicodedata
s1 = 'café' # составная форма é (U+00E9)
s2 = 'cafe\u0301' # разложенная форма e + комбинирующий акут
print('s1:', repr(s1), 's2:', repr(s2))
print('Равны ли s1 и s2?', s1 == s2) # False
# Нормализуем обе к NFC
n1 = unicodedata.normalize('NFC', s1)
n2 = unicodedata.normalize('NFC', s2)
print('После NFC:', n1 == n2) # True
# Нормализуем к NFD (все разложено)
n1_nfd = unicodedata.normalize('NFD', s1)
n2_nfd = unicodedata.normalize('NFD', s2)
print('После NFD:', n1_nfd == n2_nfd) # True
s1: 'café' s2: 'café' Равны ли s1 и s2? False После NFC: True После NFD: True
Пример 4: Перебор всех символов по категории (например, найти все знаки валют)
Можно отфильтровать символы по категории, используя unicodedata.category(). В этом примере собираются все символы из диапазона, относящиеся к категории 'Sc' (Currency Symbol).
import unicodedata
currency_symbols = []
for code in range(0x20A0, 0x20D0): # блок валютных знаков
char = chr(code)
if unicodedata.category(char) == 'Sc':
currency_symbols.append(char)
print('Некоторые символы валют:', currency_symbols[:10])
# Также можно проверить принадлежность с помощью класса 'Currency Symbol' в regex
import regex
pattern = r'\p{Sc}'
all_in_range = ''.join(chr(c) for c in range(0x20A0, 0x20D0))
found = regex.findall(pattern, all_in_range)
print('Из regex:', found[:10])
Некоторые символы валют: ['₠', '₡', '₢', '₣', '₤', '₥', '₦', '₧', '₨', '₩'] Из regex: ['₠', '₡', '₢', '₣', '₤', '₥', '₦', '₧', '₨', '₩']
Пример 5: Использование escape-последовательностей для редко используемых символов
Для вставки символов с известным кодом, но сложно вводимых с клавиатуры, применяют \u или \U. Также возможно комбинировать с именованными ссылками.
# Символ '∑' (сумма) U+2211
sigma_sum = '\u2211'
print('Сумма:', sigma_sum)
# Символ '♥' (червы) U+2665
heart = '\u2665'
print('Сердце:', heart)
# Символ из дополнительной плоскости: '?' (летающая тарелка) U+1F6F8
ufo = '\U0001F6F8'
print('UFO:', ufo)
# Можно использовать с f-строками (код динамически)
code = 0x1F600 # ?
emoticon = f'{chr(code)}'
print('Смайлик:', emoticon)
Сумма: ∑ Сердце: ♥ UFO: ? Смайлик: ?