Модуль 5 · Строки

Справочник по Python · модуль 5 · строки

Глава 5.2

5.2

Регистр
строк

capitalize(), lower() и casefold() возвращают новые строки. Первые два меняют форму текста, а casefold() предназначен прежде всего для сравнений без учёта регистра — и делает это надёжнее, чем lower().

Категория
Строковые методы
Уровень
Базовый → продвинутый
Связанные темы
Unicode, сравнения, неизменяемость
Зачем это знать
Нормализовать текст для вывода и сравнения

§1Зачем приводить регистр

Человек, набирающий текст, о регистре не думает. Пользователь введёт PYTHON, Python или python и будет считать, что написал одно и то же. Программа так не считает: для неё это три разные строки.

main.pyсравнение «как есть»
print("PYTHON" == "Python")
Выводстроки различаются
False

Нормализация регистра убирает это расхождение: обе строки приводят к одной форме и сравнивают уже её. Методы этой главы решают две разные задачи — привести текст к нужному виду для показа и привести его к единой форме для сравнения. Путать их не стоит, и §13 объясняет почему.

§2Метод возвращает новую строку

Строки в Python неизменяемы, поэтому ни один метод регистра не меняет исходную строку — все они создают новую.

main.pyисходное значение сохраняется
source = "PyThOn"
result = source.lower()

print(source)
print(result)
Выводдве разные строки
PyThOn
python
Самая частая ошибка темы

Строка text.lower() сама по себе не делает ничего: результат вычислен и выброшен. Нужно либо сохранить его — text = text.lower(), — либо сразу использовать в выражении. Ошибки при этом не будет, просто текст останется прежним. Это та же логика, что у методов списков в главе 3.10, только наоборот: там метод менял объект и возвращал None, здесь объект неизменяем и возвращается новый.

§3capitalize(): первая позиция

capitalize() делает первый символ строки заглавным. Параметров у метода нет.

main.pyимя с маленькой буквы
name = "иван"
print(name.capitalize())
Выводпервая буква поднята
Иван

Если первый символ регистра не имеет — цифра, знак, пробел, — он остаётся как есть.

main.pyстрока начинается с цифр
print("123abc".capitalize())
Выводподнимать нечего
123abc

§4capitalize() понижает остальное

Название метода описывает только половину работы. Вторая половина: все остальные буквы приводятся к нижнему регистру — независимо от того, какими они были.

main.pyне только первая буква
title = "pYTHON API"
print(title.capitalize())
Выводаббревиатура API не уцелела
Python api
Схемачто происходит с каждой позицией
p Y T H O N   A P I
↑ └─────────────────┘
│        всё это → нижний регистр
└ первая позиция → верхний регистр

Поэтому capitalize() не годится для оформления заголовков и названий, где регистр внутри строки важен. Для «каждое слово с заглавной» есть отдельный метод title(), а для проверки такой формы — istitle() из главы 5.8.

§5Пробел в начале

«Первая позиция» понимается буквально — это символ с индексом 0, а не первая буква. Пробел в начале строки полностью меняет результат.

main.pyсравнение двух порядков
text = "  pYTHON"

print(repr(text.capitalize()))
print(repr(text.strip().capitalize()))
Выводв первом случае заглавной нет вовсе
'  python'
'Python'

В первой строке первая позиция — пробел, поднимать нечего, а все буквы после неё попали под понижение. Метод не ищет первую букву после пробелов, поэтому края строки очищают заранее — strip() разбирается в главе 5.9.

Зачем здесь repr()

Обычный print() покажет python, и ведущие пробелы легко не заметить. repr() выводит строку в кавычках, ровно так, как её записал бы Python, — при отладке текста это экономит много времени.

§6lower(): нижний регистр

lower() возвращает копию строки, где все буквы приведены к нижнему регистру. Параметров нет.

main.pyсмешанный текст
text = "ПРИВЕТ, Python 3.12!"
print(text.lower())
Выводобе алфавитные системы
привет, python 3.12!

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

§7Что lower() не трогает

В примере выше изменились только буквы. Цифры 3 и 12, точка, запятая, пробел и восклицательный знак остались на месте — у них попросту нет регистра.

Что в строкеЧто делает lower()
заглавные буквыпонижает
строчные буквыоставляет как есть
цифры, знаки, пробелыне меняет
эмодзи и символыне меняет

Отсюда полезное следствие: lower() безопасно применять к любому тексту — он не может испортить неалфавитную часть.

§8Где lower() подводит

Пока речь о русском и английском, lower() достаточно. Проблема начинается там, где в языке одна буква записывается несколькими способами. Немецкая ß и сочетание ss — одно и то же слово, но разные символы.

main.pyодно слово, две записи
first = "Straße"
second = "STRASSE"

print(first.lower())
print(second.lower())
print(first.lower() == second.lower())
Выводсравнение провалилось
straße
strasse
False

lower() честно понизил обе строки, но ß так и осталась ß. Для человека это одно слово, для сравнения — разные строки. Именно эту задачу решает casefold().

§9casefold(): сравнение без регистра

casefold() тоже возвращает строку в нижнем регистре, но преобразует агрессивнее: он приводит к общей форме символы, которые в разных языках записываются по-разному.

main.pyтот же пример через casefold()
first = "Straße"
second = "STRASSE"

print(first.casefold())
print(second.casefold())
print(first.casefold() == second.casefold())
Выводтеперь слова совпали
strasse
strasse
True

Обратите внимание на длину: ß превратилась в две буквы ss. Результат casefold() может быть длиннее исходной строки — для сравнения это не важно, а вот для показа пользователю уже важно.

§10Греческая сигма

Немецкая ß — не единственный случай. В греческом одна и та же буква сигма пишется по-разному в конце слова и в середине.

main.pyдве формы одной буквы
word = "ΣΙΣΥΦΟΣ"

print(word.lower())
print(word.casefold())
Выводразные последние символы
σισυφος
σισυφοσ

lower() поступает грамотно с точки зрения языка: в конце слова он ставит конечную сигму ς. casefold() поступает грамотно с точки зрения сравнения: обе формы приводит к обычной σ, чтобы слово совпало само с собой в любой записи.

Это и есть разница между двумя методами в одной фразе: lower() сохраняет правила языка, casefold() их намеренно стирает ради сопоставимости.

§11lower() или casefold()

ЗадачаМетодПочему
показать текст строчными буквамиlower()сохраняет письменные нормы языка
сравнить ввод пользователяcasefold()сводит варианты записи к одному
поиск по тексту без учёта регистраcasefold()то же основание
сделать первую позицию заглавнойcapitalize()оформление, а не сравнение
записать логин или e-mail в базуlower()результат увидит человек

Практическое правило: текст для глаз — lower(), текст для == — casefold(). Для русского и английского они дают одинаковый результат, поэтому разница проявится не на ваших тестах, а на реальных данных.

§12Обе стороны сравнения

Нормализация помогает, только если применена к обеим строкам. Одностороннее приведение оставляет ту же проблему.

main.pyприведена только левая часть
entered = "PYTHON"
expected = "Python"

print(entered.casefold() == expected)
print(entered.casefold() == expected.casefold())
Выводработает только симметричная нормализация
False
True

В первой строке слева python, справа Python — совпадения нет. Правило простое: один и тот же метод применяют к обеим сторонам сравнения.

§13Нормализовать — не значит хранить

Соблазн понятен: привести имя пользователя к нижнему регистру один раз и хранить уже нормализованным. Но тогда исходная форма теряется навсегда.

Схемадве роли одной строки
что ввёл человек:   "Иван Петров"    → хранить и показывать
для поиска:         "иван петров"    → сравнивать

Обычная практика — хранить исходный текст, а нормализованную форму использовать только для поиска и сравнения. Особенно это касается casefold(): он может изменить саму запись слова, и показывать пользователю strasse вместо введённого Straße уже неверно.

§14Порядок методов

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

main.pyочистка, нормализация, оформление
raw = "  pYTHON API  "

clean = raw.strip().lower()
label = clean.capitalize()

print(repr(clean))
print(repr(label))
Выводдва результата под разные задачи
'python api'
'Python api'
ШагЧто на входеЧто на выходе
raw—' pYTHON API '
.strip()' pYTHON API ''pYTHON API'
.lower()'pYTHON API''python api'
.capitalize()'python api''Python api'

Общее правило цепочки: сначала убирают лишнее (strip()), затем приводят регистр, и только потом оформляют.

§15Регистр и сортировка

Глава 5.1 показала, что sorted() сравнивает кодовые точки, из-за чего заглавные буквы оказываются раньше строчных. Методы этой главы дают решение.

main.pyсортировка без учёта регистра
words = ["Яблоко", "арбуз", "Ананас"]

print(sorted(words))
print(sorted(words, key=str.lower))
Выводвторой порядок — привычный
['Ананас', 'Яблоко', 'арбуз']
['Ананас', 'арбуз', 'Яблоко']

Аргумент key означает «сравнивать не сами слова, а результат str.lower от них». При этом в списке остаются исходные слова — меняется только правило сравнения. Подробно key разбирается в главе 6.10.

§16Частые ошибки

Что написаноЧто произойдётКак правильно
text.lower() отдельной строкойрезультат выброшен, text прежнийtext = text.lower()
ждать от capitalize() сохранения остальных букввся строка после первой позиции станет строчнойдля заголовков — title()
" текст".capitalize()заглавной не будет вовсе: первая позиция — пробелtext.strip().capitalize()
lower() для сравнения многоязычного текста"Straße" и "STRASSE" не совпадутcasefold() с обеих сторон
casefold() для показа именизапись слова может изменитьсяпоказывать исходную форму
нормализовать одну сторону сравнениярезультат зависит от формы второй строкиприменить метод к обеим
text.lower без скобоксравнение с методом, а не с текстом — всегда Falsetext.lower()
capitalize() с аргументомTypeError: метод не принимает параметроввызывать с пустыми скобками

§17Проверьте себя

Меняет ли lower() исходную строку?

Нет. Строки неизменяемы, метод возвращает новую строку — её нужно сохранить или сразу использовать.

Почему "pYTHON API".capitalize() даёт "Python api"?

Метод поднимает первый символ и одновременно понижает все остальные, независимо от их исходного регистра.

Почему " PYTHON".capitalize() не даёт " Python"?

Первая позиция — пробел, у него нет регистра. Буквы после неё попадают под понижение, и заглавной не остаётся.

Когда casefold() обязателен, а lower() недостаточен?

Когда в тексте возможны символы, записываемые по-разному: немецкая ß против ss, две формы греческой сигмы. Для сравнения нужна единая форма.

Почему casefold() не стоит использовать для отображения?

Он может изменить саму запись слова и даже его длину: Straße превращается в strasse.

Что не так с entered.casefold() == expected?

Нормализована только левая сторона. Метод нужно применить к обеим строкам.

§18Шпаргалка

Первая позицияtext.capitalize()
Нижний регистрtext.lower()
Для сравненияtext.casefold()
Сравнить без регистраa.casefold() == b.casefold()
Очистка и регистрtext.strip().lower()
Сортировкаsorted(words, key=str.lower)
Сохранить результатtext = text.lower()

Итог главы

Все три метода создают новые строки и не меняют исходную. capitalize() поднимает первую позицию и понижает всё остальное, поэтому для заголовков не годится. lower() даёт строчную форму с сохранением языковых норм — это выбор для текста, который увидит человек. casefold() сводит разные записи одного символа к общей форме и потому надёжнее в сравнениях, но менять им текст для показа нельзя.

Глава 5.2 · Регистр строк · Справочник по Python Автор: Макаров Максим Николаевич