Работа с 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: ?
Смайлик: ?
  

Unicode символ в Python - comments

En
Unicode символ python (python)