# Строки в Python: обработка текста для ЕГЭ

> Срезы, методы и цикл с накопителем: считаем гласные, ищем самую длинную цепочку символов, сдвигаем буквы через ord и chr и красиво выводим ответ через f-строки.

**Информатика, 11 класс.** Урок бесплатного онлайн-самоучителя «ШкольныйГид». Обновлено: 2026-10-01.

Страница урока: https://shkolniygid.ru/informatika/11-klass/stroki-python-11/

Задание 24 ЕГЭ — одна и та же сцена: в файле лежит строка из нескольких тысяч символов, и нужно найти в ней закономерность. Самая длинная цепочка одинаковых букв, череда цифр, количество пар «буква и цифра». Вручную такое не считают, а программа помещается в десять строк — если владеть срезами, методами, накопителем и кодами символов. Урок собирает кирпичики на коротких словах и показывает ловушки экзамена.


### Индексация и срезы


Возьмём слово s = "программа". Символы считаются с нуля: s[0] — это "п", s[4] — снова "р", а последний, девятый по счёту, имеет индекс 8. Отрицательные индексы идут с конца: s[-1] — "а", s[-2] — "м". Длину даёт len: len(s) — 9. Запомни асимметрию: одиночный индекс за границей, s[9] или s[-10], падает с ошибкой IndexError. У срезов характер мягкий — сейчас увидишь.


Срез s[a:b] вырезает символы с индекса a по b - 1: правая граница всегда за кадром, поэтому длина среза равна b - a. Опущенная граница — это «от начала» или «до конца»: s[:4] — первые четыре символа, s[5:] — всё с пятого индекса. Третий параметр — шаг: s[::3] берёт каждый третий символ, а s[::-1] идёт с шагом минус один и возвращает строку наоборот — формулу разворота выучи как таблицу умножения. А s[1:-1] — строка без первого и последнего символа.


| Выражение | Результат | Пояснение |
| --- | --- | --- |
| len(s) | 9 | в слове девять букв |
| s[0] | п | нумерация с нуля |
| s[-1] | а | отрицательный индекс считает с конца |
| s[2:6] | огра | индексы 2, 3, 4, 5; правая граница не входит |
| s[:4] | прог | без левой границы — от начала строки |
| s[5:] | амма | без правой границы — до конца строки |
| s[::3] | пгм | шаг три: индексы 0, 3 и 6 |
| s[::-1] | аммаргорп | шаг минус один — разворот |
| s[1:-1] | рограмм | без первого и последнего символа |

*Срезы строки s = "программа"*


> **Ловушки срезов.** Первая и самая коварная: срез за границами не падает, а тихо режет — s[100:] вернёт пустую строку, и ошибка останется незамеченной. Вторая: правая граница не входит — s[2:6] содержит четыре символа, а не пять. Третья: не путай s[:-1] — строку без последнего символа — и s[::-1] — разворот. Четвёртая: IndexError бывает у одиночного индекса, но не у среза.


### Методы строк


Метод find ищет подстроку и возвращает индекс первого вхождения: "информатика".find("фор") — это 2. Если подстроки нет, вернётся -1: не ошибка, а сигнал для цикла «нашёл — обработал — ищи дальше». Собрат index при неудаче бросает ValueError, поэтому обычно выбирают find. count считает неперекрывающиеся вхождения, replace заменяет сразу все. Главный факт про все методы: оригинал они не трогают. Строки неизменяемы, запись s[0] = "П" вызовет TypeError, а результат нужно присваивать: s = s.replace(...) — иначе замена молча растворится.


split режет строку по разделителю и отдаёт список: "5 10 15".split() — это ["5", "10", "15"]; вызов без аргумента режет по любым пробелам подряд — так читают несколько чисел из строки. Обратная операция — join: "-".join(["2026", "10", "01"]) соберёт дату обратно. strip убирает пробелы по краям — обязательный шаг при чтении файла: справа висит невидимый перевод строки. upper и lower меняют регистр целиком, а оператор in проверяет принадлежность: "и" in "гроза" — True.


| Метод | Что делает | Пример | Результат |
| --- | --- | --- | --- |
| find | индекс первого вхождения или -1 | "информатика".find("фор") | 2 |
| count | число неперекрывающихся вхождений | "аааа".count("аа") | 2 |
| replace | новая строка со всеми заменами | "1-2-3".replace("-", "+") | "1+2+3" |
| split | список кусков после разреза | "5 10 15".split() | ["5", "10", "15"] |
| join | строка, склеенная из списка | ".".join(["192", "168", "1", "1"]) | "192.168.1.1" |
| upper и lower | перевод регистра целиком | "PyThOn".upper() | "PYTHON" |
| strip | копия без пробелов по краям | " привет ".strip() | "привет" |

*Методы строк: что делают и что возвращают*


> **Ловушки методов.** Первая: методы возвращают новую строку, а исходную не меняют — вызов s.upper() без присваивания ничего не изменит, когда результат нужен, пиши s = s.upper(). Вторая: count не считает перекрытия — "аааа".count("аа") даст 2, хотя пар на глаз три. Третья: find и index не близнецы — первый вернёт -1, второй бросит ValueError. Четвёртая: split без аргумента режет только по пробелам — разделитель указывают явно.


*[Интерактив: Собери пары: метод и его результат — доступен на странице урока]*


### Перебор символов и накопление


Шаблон «цикл плюс накопитель» — главный инструмент задания 24. Заводим счётчик до цикла, проходим for c in s: — переменная c получает сами символы — и обновляем по условию. Подсчёт гласных:

s = "гроза"
k = 0
for c in s:
    if c in "аеёиоуыэюя":
        k += 1
print(k)

В "гроза" две гласных, программа выведет 2. Условие меняется, каркас — никогда: цифры ловит c.isdigit(), буквы — c.isalpha(), произвольный набор — проверка in.


Второй типовой сюжет — рекорд: самая длинная цепочка одинаковых символов подряд. Нужны три переменные: prev — предыдущий символ, cur — длина текущей цепочки, best — рекорд. Совпал с prev — cur растёт, не совпал — cur возвращается к единице. После сравнения обновляем рекорд, в конце шага пишем символ в prev.

s = "aabbbba"
prev = s[0]
cur = 1
best = 1
for c in s[1:]:
    if c == prev:
        cur += 1
    else:
        cur = 1
    if cur > best:
        best = cur
    prev = c
print(best)

Программа выведет 4 — цепочка из четырёх букв "b". Счётчики стартуют с единицы: первый символ уже цепочка, поэтому best = 0 на старте — ошибка.


**Прогон алгоритма на строке aabbbba**

1. Старт: prev = "a", cur = 1, best = 1 — первый символ уже цепочка.
2. c = "a": совпал с prev — cur = 2, рекорд обновился, best = 2.
3. c = "b": не совпал — cur = 1, новая цепочка; prev стал "b".
4. c = "b": совпал — cur = 2, best пока 2.
5. c = "b": совпал — cur = 3, best = 3.
6. c = "b": совпал — cur = 4, best = 4.
7. c = "a": не совпал — cur = 1, но рекорд уже 4. Цикл кончился, print(best) выводит 4.

*Колонки cur и best в черновике должны повторить эти шаги.*


> **Совет.** Шаблон «максимальная цепочка» выучи наизусть: prev = s[0], cur = 1, best = 1, цикл по s[1:], внутри — сравнение, сдвиг или сброс cur, обновление best, запоминание prev. На экзамене каркас записывается за минуту: между вариантами задания меняется только условие в if. Вместо изобретения цикла на свежую формулировку подставляешь условие в готовый скелет и идёшь дальше.


Условие в if — единственная строка, которая меняется между вариантами задания. Цепочка цифр: c.isdigit() and prev.isdigit(). Чередование «буква и цифра»: c.isdigit() != prev.isdigit() — сравниваются типы, а не символы. Цепочка из набора: c in "ABC" and prev in "ABC". Встречается и вопрос «сколько цепочек длины хотя бы k» — тогда нужна четвёртая переменная — счётчик начал цепочек. Прогоняй каждый вариант на короткой строке руками.


### Коды символов: ord и chr


Функция ord возвращает код символа, chr собирает символ из кода: ord("A") — 65, chr(66) — "B". Латиница лежит сплошным куском: заглавные от "A" до "Z" занимают коды 65..90, строчные от "a" до "z" — 97..122. Поэтому «сдвинуть букву по алфавиту» — это арифметика: ord(c) - ord("a") даёт номер буквы, если считать "a" нулевой. Русские строчные от "а" до "я" идут подряд — коды 1072..1103. Строки сравниваются по кодам, поэтому "B" меньше "a": 65 меньше 97.


Шифр Цезаря сдвигает каждую букву на фиксированное число позиций. Формула на один символ:

k = 3
c = "x"
new = chr((ord(c) - ord("a") + k) % 26 + ord("a"))
print(new)

Три шага: вычесть базу, прибавить сдвиг, вернуть базу. Остаток % 26 заворачивает переход через конец алфавита: у "x" смещение 23, плюс три — 26, остаток ноль, на выходе "a". Расшифровка отличается только знаком: k меняется на -k. Если переход через конец гарантированно не случится, хватит chr(ord(c) + k).


*[Интерактив: Разбор шифра: буква y со сдвигом 3 — доступен на странице урока]*


С русскими буквами та же формула требует внимательности. Букв в алфавите 33, но между "а" и "я" в кодах лежат только 32: "ё" стоит отдельно, с кодом 1105. Первая ловушка: формула с остатком % 33 может выдать код 1104 — символ существует, но это не буква русского алфавита. Если "ё" в данных заведомо не встречается, сдвигают с остатком 32. Вторая ловушка: "ё" ломает и разность — ord("ё") - ord("а") равен 33, хотя по алфавиту "ё" седьмая. Строгая обработка заводит строку-алфавит и ищет позиции буквы через alphabet.find(c). Чаще хватает оговорки про отсутствие "ё".


### f-строки и format


Собирать ответ из кусков удобнее всего f-строкой: перед кавычкой ставится буква f, а выражения пишутся в фигурных скобках — f"Цепочка длины {best}" подставит значение переменной. Внутри скобок живут и вычисления: f"{2 * 3 + 1}" даст "7". Для дробных чисел есть округление в выводе: f"{3.14159:.2f}" вернёт "3.14" — две цифры после точки, само число не меняется. f-строки избавляют от склейки со str() и читаются как готовое предложение: print(f"Максимум: {best}"). Метод format делает то же: "{:.2f}".format(3.14159).


*[Интерактив: Куда уходит результат? — доступен на странице урока]*


*[Интерактив: Верно или нет? — доступен на странице урока]*


*[Интерактив: Вставь пропуски — доступен на странице урока]*


**Индексация** — доступ к символу по номеру: s[0] первый, s[-1] последний
**Срез** — s[a:b] — символы с a по b - 1; третий параметр — шаг
**Неизменяемость** — методы не меняют оригинал, а возвращают новую строку
**prev, cur, best** — три переменные шаблона «максимальная цепочка»
**f-строка** — шаблон вывода с округлением: f"{x:.2f}"


Собери всё в программу для файла: open читает строку, strip чистит края, дальше — цикл с prev, cur и best, в конце печать через f-строку. Самоконтроль без компьютера: "программа"[2:6] — это "огра", "аааа".count("аа") — два, в "гроза" две гласных, шифр со сдвигом 3 превращает "x" в "a". Если проверки сошлись — шаблоны урока усвоены.


## Частые вопросы

### Почему "аааа".count("аа") даёт 2, а не 3?

Метод считает неперекрывающиеся вхождения: найдя "аа" с нулевой позиции, поиск продолжается с индекса 2. Вариант, начинающийся с индекса 1, целиком лежит внутри уже найденного куска и не учитывается, поэтому остаются только позиции 0 и 2.


### Чем find отличается от index?

Оба возвращают индекс первого вхождения подстроки. Разница проявляется при неудаче: find вернёт -1, а index бросит ValueError, который без try и except уронит программу. В задачах с файлом обычно берут find — проверка результата на -1 проще обработки исключения.


### Можно ли заменить один символ строки присваиванием?

Нет: строки неизменяемы, запись s[0] = "П" вызовет TypeError. Собери новую строку и присвой её той же переменной: s = "П" + s[1:] меняет первый символ через склейку. Тот же принцип у replace и upper — они возвращают копию, а оригинал не трогают.


### Почему для цепочки нужны ровно три переменные?

prev отвечает за сравнение соседей, cur — за длину текущей цепочки, best — за рекорд. Без prev непонятно, с чем сравнивать текущий символ, без cur — не от чего считать рекорд, а без best ответ сотрётся при следующем сбросе счётчика. Три переменные заводят до цикла и инициализируют первым символом и единицами.


## Проверь себя (вопросы и ответы)

#### Вопрос 1: Что вернёт выражение "молоко".find("ол")?
- ✅ 1
- ☐ 2
- ☐ -1
- ☐ 4

*Пояснение: Ищем с начала строки: "м" на индексе 0 не начало куска, а на индексе 1 уже идёт "ол". Метод возвращает индекс первого вхождения.*


#### Вопрос 2: Какие вызовы вернут строку?
- ✅ "текст".upper()
- ✅ "текст".replace("т", "п")
- ☐ "текст".count("т")
- ☐ "текст".split("к")

*Пояснение: upper и replace возвращают новую строку. count выдаёт число, split — список кусков: такие результаты строке не равны.*


#### Вопрос 3: Строка s = "программа". Что выведет команда print(s[3:6])? Впиши символы без кавычек.
**Ответ:** гра

*Пояснение: Срез берёт индексы 3, 4 и 5 — символы "г", "р" и "а". Правая граница 6 не входит, получится "гра".*


#### Вопрос 4: Значение выражения "аааа".count("аа") равно 3.
- ☐ Правда
- ✅ Неправда

*Пояснение: Метод считает только неперекрывающиеся вхождения: взяв "аа" с нулевой позиции, поиск продолжится с индекса 2. Получится 2, а не 3.*


#### Вопрос 5: Расставь действия алгоритма поиска самой длинной цепочки одинаковых символов.
**Правильный порядок:** завести prev, cur и best по первому символу → сравнить текущий символ с prev → увеличить cur при совпадении или сбросить в 1 → обновить best, если cur стал больше → записать текущий символ в prev

*Пояснение: Сначала три переменные по первому символу, затем для каждого следующего: сравнение, сдвиг или сброс счётчика, обновление рекорда и запоминание символа.*


#### Вопрос 6: Разложи вызовы по типу результата.
- **строка:** s.upper(), "-".join(["a", "b"])
- **число:** s.find("а"), s.count("б")
- **список:** s.split(",")

*Пояснение: upper и join собирают новую строку, find и count возвращают число вхождений или позицию, split режет в список. Тип результата виден из смысла метода.*


#### Вопрос 7: Дополни правила работы со строками.
Строки неизменяемы: метод replace возвращает **новую** строку, а оригинал не трогает. Метод find при неудаче вернёт **-1**, а его собрат index бросит исключение. Перевернуть строку помогает срез **s[::-1]**.

*Пояснение: Неизменяемость означает, что любой метод отдаёт новый объект. find сообщает неудачу значением -1, index — ValueError. Разворот — срез с шагом минус один.*


## Тренажёр

На [странице тренажёра](https://shkolniygid.ru/informatika/11-klass/stroki-python-11/trenazher/) — 4 типов задач с бесконечными вариантами чисел, проверкой ответа и разбором каждого шага.
