Справочник по Python · модуль 5 · строки
Глава 5.1
Unicode, ord()
и chr()
Строка Python хранит символы Unicode, и у каждого символа есть номер — кодовая точка. ord() получает номер символа, chr() выполняет обратное преобразование. Через эти номера работают сравнение строк, сортировка и любые посимвольные вычисления.
- Категория
- Строки и Unicode
- Уровень
- Базовый → продвинутый
- Связанные темы
- Строки, числа, кодировки, сортировка
- Зачем это знать
- Связывать символы с числовыми кодовыми точками
§1Зачем символу номер
Компьютер не хранит буквы. Он хранит числа, а буква — это договорённость о том, какое число как показывать на экране. Unicode и есть такая договорённость: единая таблица, где каждому символу мира назначен свой номер.
Знать этот номер нужно не из любопытства. Через него объясняются вещи, которые иначе выглядят необъяснимо:
- почему
"Я" < "а"даётTrue, хотя «я» — последняя буква алфавита; - почему
sorted()ставит слова с заглавной буквы раньше остальных; - как проверить, что символ — цифра, не сравнивая его с десятью вариантами;
- почему у русской буквы
len()равен единице, а в файле она занимает два байта.
Все четыре ответа — в этой главе.
§2Символ и кодовая точка
Кодовая точка — номер символа в таблице Unicode. Его записывают в двух видах: как U+0041 (шестнадцатеричная запись, принятая в стандарте) и как обычное десятичное число 65, с которым работает Python.
| Символ | Кодовая точка | Десятичное число |
|---|---|---|
0 | U+0030 | 48 |
A | U+0041 | 65 |
a | U+0061 | 97 |
Я | U+042F | 1071 |
€ | U+20AC | 8364 |
Обратите внимание на порядок: цифры идут раньше заглавных латинских букв, заглавные — раньше строчных, кириллица — заметно позже всей латиницы. Этот порядок и определяет результат любого сравнения строк.
ord()
"A" ─────────→ 65
←─────────
chr()
§3ord(): символ → число
ord(char) принимает строку длиной один символ и возвращает её кодовую точку целым числом.
print(ord("A")) print(ord("Я")) print(ord("€"))
65 1071 8364
Название функции — от английского ordinal, «порядковый номер». Возвращается всегда int, с которым можно делать обычную арифметику.
§4chr(): число → символ
chr(number) делает обратное: принимает целое число и возвращает строку из одного символа с таким номером.
print(chr(65)) print(chr(1071)) print(chr(8364))
A Я €
Результат — именно строка, а не «символ»: отдельного типа для одного символа в Python нет. Поэтому к результату chr() применимы все строковые методы.
§5Обратимость преобразования
Две функции строго обращают друг друга: chr(ord(x)) всегда возвращает исходный символ.
symbol = "Ж" code_point = ord(symbol) restored = chr(code_point) print(code_point) print(restored) print(restored == symbol)
1046 Ж True
Легко перепутать направление. Подсказка в названиях: ord даёт ordinal — номер, значит на выходе число. chr даёт chraracter — символ, значит на выходе строка.
§6Ровно один символ
Требование «строка длиной 1» соблюдается строго. Ни пустая строка, ни строка из двух букв не подойдут.
print(ord("AB"))
Traceback (most recent call last):
File "main.py", line 1, in <module>
print(ord("AB"))
^^^^^^^^^
TypeError: ord() expected a character, but string of length 2 found
Пустая строка даёт то же исключение со словами string of length 0. Чтобы получить коды нескольких символов, строку перебирают — об этом §9.
§7Допустимый диапазон chr()
Unicode охватывает кодовые точки от 0 до 0x10FFFF — то есть до 1 114 111 включительно. Число за этой границей символа не обозначает.
print(chr(0x110000))
ValueError: chr() arg not in range(0x110000)
Разница в типах исключений не случайна: TypeError означает «передано не то что нужно», ValueError — «тип верный, но значение недопустимо». Отрицательное число тоже даёт ValueError.
§8Кодовая точка в литерале
Символ можно записать прямо в строке, не вызывая chr(), — через escape-последовательность с шестнадцатеричным кодом.
latin = "\u0041" cyrillic = "\u042f" emoji = "\U0001F642" print(latin, cyrillic, emoji)
A Я 🙂
| Запись | Сколько цифр | Пример |
|---|---|---|
\u | ровно 4 | "\u042F" → Я |
\U | ровно 8 | "\U0001F642" → 🙂 |
\x | ровно 2 | "\x41" → A |
Количество цифр обязательное: "\u42F" — синтаксическая ошибка, нужно "Я" с ведущим нулём. Регистр самих цифр значения не имеет.
§9Коды всей строки
ord() работает с одним символом, поэтому для строки её перебирают.
text = "Код" codes = [ord(symbol) for symbol in text] print(codes)
[1050, 1086, 1076]
Обратная сборка требует join(): chr() даёт отдельные строки, и их нужно склеить.
codes = [1050, 1086, 1076] print("".join(chr(code) for code in codes))
Код
Метод join() подробно разбирается в главе 5.9. Здесь достаточно знать, что он склеивает набор строк в одну.
§10Сравнение строк
Теперь можно ответить на первый вопрос из §1. Операторы < и > сравнивают строки посимвольно, а каждую пару символов — по кодовым точкам.
print("A" < "a") print(ord("A"), ord("a"))
True 65 97
Никакой «алфавитности» здесь нет — есть только числа. Заглавная A меньше строчной a просто потому, что её номер меньше.
§11Сортировка и регистр
Из того же правила следует поведение, которое регулярно принимают за ошибку сортировки.
words = ["Яблоко", "арбуз", "Ананас"] print(sorted(words))
['Ананас', 'Яблоко', 'арбуз']
Причина видна по кодам: ord("А") — 1040, ord("Я") — 1071, а ord("а") — уже 1072. Все заглавные кириллические буквы идут до всех строчных, поэтому «арбуз» с маленькой буквы проигрывает даже «Яблоку».
Сортировать по приведённой к одному регистру форме: sorted(words, key=str.lower). Тогда сравниваются ананас, арбуз, яблоко, и результат совпадает с ожиданиями. Аргумент key — тема главы 6.10.
§12Арифметика по кодам
Раз кодовые точки — числа, с ними работают обычные операции. Цифры в Unicode идут подряд от 0 (48) до 9 (57), и это даёт две полезные записи.
symbol = "7" print(ord("0") <= ord(symbol) <= ord("9")) print(ord(symbol) - ord("0"))
True 7
Буквы алфавита тоже идут подряд, поэтому так же вычисляют номер буквы в алфавите.
print(ord("г") - ord("а") + 1)
4
В обычном коде для проверки цифры удобнее готовый метод symbol.isdigit() из главы 5.7. Приём с кодами нужен там, где важно само числовое расстояние между символами.
В кириллице подряд идут только а–я (1072–1103). Буква ё имеет код 1105 и в этот ряд не попадает, поэтому формула «номер буквы» на ней ломается.
§13Сдвиг символов
Классическое применение пары функций — сдвинуть каждый символ на несколько позиций. На этом построен шифр Цезаря.
text = "abc" result = "" for symbol in text: result += chr(ord(symbol) + 1) print(result)
bcd
ord(symbol)переводит символ в число.- К числу прибавляется сдвиг — получается кодовая точка соседнего символа.
chr()возвращает результат обратно в строку.
Настоящий шифр Цезаря требует ещё и «заворачивания» алфавита: после z должна снова идти a, а не следующий по таблице символ {. Для этого сдвиг берут по остатку от деления на длину алфавита.
§14Символ — это не байт
Последний вопрос из §1. Кодовая точка — номер символа в таблице, а не то, как символ лежит в файле или в сети. Хранение — отдельный шаг, и там один символ вполне может занимать несколько байтов.
letter = "Я" print(len(letter)) print(len(letter.encode("utf-8")))
1 2
Для Python это одна буква, для файла — два байта. Перевод символов в байты и обратно — тема главы 5.4.
§15Частые ошибки
| Что написано | Что произойдёт | Как правильно |
|---|---|---|
ord("AB") | TypeError: длина аргумента равна 2 | передать один символ или перебрать строку |
ord("") | TypeError: длина аргумента равна 0 | проверить, что строка не пуста |
ord(65) | TypeError: ожидается строка | chr(65) — направление перепутано |
chr("65") | TypeError: ожидается целое число | chr(65) без кавычек |
chr(0x110000) | ValueError: вне Unicode | кодовая точка от 0 до 1 114 111 |
"\u42F" | SyntaxError: нужно ровно четыре цифры | "\u042F" |
ждать алфавитный порядок от sorted() | заглавные окажутся раньше строчных | sorted(words, key=str.lower) |
| считать кодовую точку байтом | теряется различие между символом и его кодировкой | для байтов применять encode() |
§16Проверьте себя
Что возвращает ord()?
Целое число — кодовую точку единственного переданного символа Unicode.
Почему ord("ab") вызывает ошибку?
Функция принимает ровно один символ, а в строке их два. Для строки нужен перебор.
Почему "Я" < "а" истинно?
Сравниваются не буквы алфавита, а кодовые точки: у Я это 1071, у а — 1072. Все заглавные кириллические буквы идут раньше всех строчных.
Чем TypeError у ord() отличается от ValueError у chr()?
TypeError означает, что передано не то, что нужно, а ValueError — что тип верный, но значение вне допустимого диапазона.
Как получить числовое значение символа-цифры?
ord(symbol) - ord("0"): цифры идут в таблице подряд, поэтому разность даёт само число.
Почему len("Я") равен 1, а в файле буква занимает два байта?
Кодовая точка — номер символа в таблице, а не способ его хранения. Перевод в байты выполняет encode().
§17Шпаргалка
ord("A") # 65chr(65) # "A"[ord(ch) for ch in text]"".join(chr(c) for c in codes)"\u042F" # "Я"ord(ch) - ord("0")chr(ord(ch) + 1)0 … 1_114_111Итог главы
ord() переводит один символ в его кодовую точку, chr() выполняет обратное преобразование, и вместе они полностью обратимы. Через кодовые точки объясняется поведение сравнения и сортировки строк: Python сравнивает номера символов, а не буквы алфавита. Кодовая точка при этом описывает символ в таблице Unicode, но не способ его хранения — за это отвечают кодировки.