Циклы и строки в Python: разбор текста на слова
Разбор текста начинается со split: строка превращается в список слов, цикл считает, ищет и собирает отчёт.
Редакция Питоники
Текст — самая ходовая работа для программы: логи, сообщения, имена файлов, ввод пользователя. Цикл по строке — это цикл по её символам, а разбор текста начинается со split: строка превращается в список слов. На этом уроке соединяем циклы и строки в рабочие связки: считаем слова и гласные, ищем подстроки в журнале, нумеруем строки и собираем маленький отчёт, который отвечает на вопрос о данных.
Слова строки: split
Строка сама по себе — одно целое. Метод split режет её по пробелам и отдаёт список слов, с которым цикл уже умеет работать:
line = 'Мама мыла раму утром'
words = line.split()
print(len(words))
for w in words:
print(w, '-', len(w), 'букв')
4 Мама - 4 букв мыла - 4 букв раму - 4 букв утром - 5 букв
split() без аргумента режет строку по пробелам, порядок слов сохраняется. Дальше это обычный список: len(words) считает слова, а цикл for w in words ходит по каждому, и len(w) меряет длину слова. Связка «split — потом for» — самый частый вход в обработку текста: после неё доступны все приёмы из уроков про списки.
Подсчёт: гласные и не только
Цикл по строке идёт по символам: переменная ch по очереди принимает каждый символ строки. Проверка принадлежности ch in 'аеёиоуыэюя' отвечает на вопрос, входит ли символ в набор гласных:
text = 'Мама мыла раму'
vowels = 0
for ch in text.lower():
if ch in 'аеёиоуыэюя':
vowels += 1
print(vowels)
6
Аккумулятор vowels стартует с нуля и растёт на единицу за каждую гласную — тот же счётчик из урока про аккумуляторы, только шаг цикла здесь не элемент списка, а символ строки. lower() приводит текст к нижнему регистру перед сравнением: без него заглавная М из начала предложения ускользнула бы от проверки, потому что символ М и символ м — разные символы.
Список строк: поиск подстроки
Список строк — почти файл: каждая строка — запись журнала. Оператор in работает в двух ролях: в for line in log он организует перебор, а внутри if проверяет, входит ли подстрока в строку:
log = [
'сервер запущен',
'ошибка соединения',
'запрос обработан',
'ошибка соединения',
]
errors = 0
for line in log:
if 'ошибка' in line:
errors += 1
print(errors)
2
Проверка 'ошибка' in line отвечает True, если подстрока входит в строку, где бы она ни стояла: в начале, в конце, в середине. Несовпавшие строки просто не трогают счётчик — это та же фильтрация, что в уроке про continue, только без явного пропуска итерации.
Счётчик сказал, сколько ошибок, но не сказал, где они. Номер строки даёт enumerate: он выдаёт пары «номер — элемент».
log = [
'сервер запущен',
'ошибка соединения',
'запрос обработан',
'ошибка соединения',
]
for i, line in enumerate(log, start=1):
if 'ошибка' in line:
print('строка', i, ':', line)
строка 2 : ошибка соединения строка 4 : ошибка соединения
enumerate(log, start=1) нумерует итерации с единицы, поэтому в отчёте человеческие номера строк — вторая и четвёртая. Распаковка i, line разбирает каждую пару на две переменные: внутри цикла доступны и адрес строки, и её содержимое. Подробный разбор enumerate был отдельным уроком про индекс и значение.
Самое длинное слово
Классическая задача на аккумулирование: пройтись по словам и удержать самое длинное из виденных.
text = 'мы программируем на питоне и это удобно'
longest = ''
for w in text.split():
if len(w) > len(longest):
longest = w
print(longest)
программируем
Переменная longest стартует пустой строкой: у неё нулевая длина, поэтому первое же слово её перезапишет. Условие строгое, знак больше: при равных длинах побеждает первое слово, второе равное по длине результат не тронет. Этот же каркас решает обратные задачи — самое короткое слово, самая ранняя дата, первое слово на заданную букву: меняется только сравнение.
Многострочный текст
Настоящие тексты многострочные: файлы, сообщения, отчёты. Их режут на строки методом splitlines, а каждую строку — на слова уже знакомым split:
text = 'первая строка\nвторая строка длиннее\nтретья'
total = 0
for line in text.splitlines():
total += len(line.split())
print(total)
6
Двойной разбор — строка за строкой, слово за словом — это каркас любого текстового отчёта: csv-файл, лог сервера и глава книги разбираются одинаково. Внешний цикл ходит по строкам, внутренний вызов split разрезает каждую на слова, аккумулятор складывает всё в один итог.
Частотный словарь: цикл, который считает повторы
От «сколько слов» до «какие слова повторяются» — один шаг, и делается он всё тем же циклом со счётчиком. Разница в том, что счётчик здесь не один, а по одному на каждое слово, и хранить их удобно в словаре.
text = 'кот и кот и программист'
words = text.split()
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1
print(counts)
{'кот': 2, 'и': 2, 'программист': 1}Словарь хранит пары «слово — сколько раз встретилось». Ключи стоят в порядке первого появления: сначала кот, потом и, потом программист. Конструкция counts.get(w, 0) + 1 — это тот же аккумулятор, только счётчик выбирается по ключу: для нового слова get вернёт ноль, для знакомого — прежнее значение. Отсюда же растёт понимание, зачем нужен параметр по умолчанию.
text = 'кот и кот и программист'
words = text.split()
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1
top = ''
top_count = 0
for w, c in counts.items():
if c > top_count:
top_count = c
top = w
print('чаще всего:', top, '-', top_count)
чаще всего: кот - 2
Каркас максимума поверх счётчика: перебираем пары «слово — количество» и держим лучшее. Кот и и набрали по два, программист — один, и при равных счётах побеждает первый встреченный: сравнение строгое, знак больше. Всё это — два цикла и один словарь, ничего нового.
Буквы против символов
Считать символы строки просто, а вот отличить буквы от пробелов и знаков — уже интереснее. Метод isalpha() отвечает на вопрос «это буква?» для одного символа, и цикл по строке превращает это в подсчёт.
s = 'Привет, мир! 123'
letters = 0
for ch in s:
if ch.isalpha():
letters += 1
print('символов всего:', len(s))
print('букв:', letters)
символов всего: 16 букв: 9
Девять букв против шестнадцати символов: семь позиций заняли пробелы, запятая, восклицательный знак и три цифры. Метод isalpha() работает и с кириллицей, и с латиницей — ему всё равно, какой алфавит. Родные проверки работают и для цифр (isdigit()), и для знаков препинания (ispunctuation()), и для пробелов (isspace()).
text = 'Привет, мир! Как дела?'
marks = 0
for ch in text:
if ch in ',.!?':
marks += 1
print('знаков препинания:', marks)
знаков препинания: 3
Три запятые-знака: запятая, восклицательный и вопросительный. Вариант со списком символов в строке работает и для конкретного набора знаков, а ispunctuation() посчитал бы их все — вместе с кавычками и тире, которых в этом тексте нет, но которые в живой речи встречаются постоянно.
Разбор по разделителю
split() без аргумента режет по пробелам — это удобно для текста. Но данные часто приходят в других форматах: csv-строка, разделённая запятыми, путь к файлу с обратными слэшами, теги через запятую. Для них у split есть второй аргумент — разделитель.
csv = 'a,b,c'
print(csv.split(','))
print(csv.split(',', 1))
['a', 'b', 'c'] ['a', 'b,c']
Второй вызов отличается только числом разбиений: maxsplit=1 режет строку один раз и оставляет хвост целиком. Это ровно то, что нужно, когда вы знаете, что в хвосте могут быть запятые: разделитель один, а остальное — данные. Число в скобках можно опустить, по умолчанию строка режется до конца.
Регистр: почему lower решает половину задач
Проверка подстроки в тексте выглядит простой, но спотыкается о регистр: 'ошибка' не найдётся в строке 'Ошибка'. Приводить текст к нижнему регистру перед сравнением — стандартный приём, и он же объясняет, почему в реальных логах ошибок находят больше, чем кажется.
line = 'Ошибка: не найден файл'
print('ошибка' in line)
print('ошибка' in line.lower())
False True
Первая проверка не нашла ничего — заглавная О не совпала со строчной о. Вторая нашла, потому что lower() привёл обе стороны к одному регистру. Тот же приём работает для подсчёта: сравнивать с приведённой строкой или приводить в цикле — выбор только в том, где стоит вызов.
Чистка перед разбором
Реальные строки приходят с мусором: лишние пробелы по краям, пустые строки между абзацами, табы вместо пробелов. Разбор до чистки даёт мусорные слова и лишние элементы в списке, и все последующие счётчики считают не то.
raw = ' привет '
print(repr(raw.strip()))
print(raw.strip().split())
print(repr('a,,b'.split(',')))
'привет' ['привет'] ['a', '', 'b']
Метод strip срезает пробелы с обоих концов строки — именно края, внутренние пробелы он не трогает. Функция repr показывает результат в кавычках, и по ним видно, что пробелов больше нет: без repr пустая строка выглядела бы так же, как строка с одним пробелом. А вот split(',') оставил пустой кусок — и его придётся отфильтровать отдельно.
parts = 'a,,b'.split(',')
clean = []
for p in parts:
if p:
clean.append(p)
print(clean)
print([p for p in parts if p])
['a', 'b'] ['a', 'b']
Две записи дают один результат: цикл с continue и генератор списка с условием. Вторая короче, первая понятнее новичку. На практике я бы оставил цикл в том месте, где разбор идёт впервые, а в рабочем коде перешёл бы на генератор: чистка — это операция над коллекцией, а не действие.
Что дальше: текст становится данными
Разобранный текст — это уже не текст, а структура: список слов, словарь частот, набор чисел. Дальше с такой структурой работают обычные инструменты: сортировка, срезы, генераторы списков. Весь разбор — это мост между строками и коллекциями, а мост этот строится циклом.
| Задача | Инструмент | Где встречается |
|---|---|---|
| слова строки | split() | первый шаг почти любого разбора |
| символы строки | for ch in text | посимвольные проверки |
| буквы без знаков | ch.isalpha() | подсчёт букв и слов |
| поиск подстроки | 'слово' in line | логи, анкеты, отчёты |
| частоты | counts.get(w, 0) + 1 | анализ текста |
| разбор по разделителю | split(',') | csv, теги, пути |
| нормализация | lower(), strip() | регистр и лишние пробелы |
| Инструмент | Что делает |
|---|---|
| split() | Режет строку по пробелам в список слов |
| splitlines() | Режет многострочный текст в список строк |
| ch in 'аеёиоуыэюя' | Проверяет, входит ли символ в набор |
| 'ошибка' in line | Проверяет, входит ли подстрока в строку |
| enumerate(lines, start=1) | Выдаёт пары «номер строки — строка» |
Мини-отчёт из цикла
Соберём всё вместе: журнал заказов, из которого цикл извлекает ответ на деловой вопрос.
report = [
'заказ 1: доставлен',
'заказ 2: отменён',
'заказ 3: доставлен',
'заказ 4: доставлен',
]
delivered = 0
for line in report:
if 'доставлен' in line:
delivered += 1
print('Доставлено:', delivered)
print('Всего заказов:', len(report))
Доставлено: 3 Всего заказов: 4
Три инструмента — перебор, in и аккумулятор — сложились в программу, которая читает данные и отвечает на вопрос о них. Дальше по курсу такие отчёты станут привычными: финальный проект раздела соберёт из тех же деталей полный разбор оценок класса.
words = ['мама', 'мыла', 'раму']
line = ' '.join(words) # 'мама мыла раму'
Сначала предскажи ответ в голове — это главный навык программиста.
text = 'раз два три'
print(len(text.split()))
count = 0
for ch in 'аоа':
if ch == 'а':
count += 1
print(count)
total = ''
for w in ['а', 'б', 'в']:
total += w
print(total)
1. Что вернёт 'Мама'.split()?
2. Сколько итераций сделает цикл for ch in 'кот'?
3. Как найти строки журнала, в которых есть слово «ошибка»?
4. Что даёт enumerate(log, start=1) при переборе списка строк?
5. Зачем перед подсчётом гласных текст прогоняют через lower()?
6. Как посчитать, сколько раз каждое слово встретилось в тексте?
7. Что вернёт 'a,,b'.split(',')?
8. Зачем нужны isalpha(), isdigit() и подобные методы?
Для строки 'Изучаю циклы и массивы' выведи, сколько в ней слов, а затем посчитай и выведи, сколько в ней букв а (в любом регистре).
Как перебрать слова в строке в Python?
Разбить строку на слова через split() и пройти циклом: for w in text.split(). Каждое w — отдельное слово, len(w) даст его длину, а аккумулятор посчитает любые подходящие слова.
Урок 9 курса строк: splitКак посчитать, сколько раз символ встречается в строке?
Циклом по строке с аккумулятором: счётчик стартует с нуля и растёт на каждый совпавший символ. Для готовой строки есть и метод count: text.count('а') сделает то же самое одним вызовом.
Чем split отличается от splitlines?
split() режет по пробелам на слова, splitlines() — по переводам строки на строки текста. Многострочный разбор обычно двухступенчатый: сначала splitlines, потом split для каждой строки.
Как в цикле получить и номер строки, и её содержимое?
enumerate со start=1: for i, line in enumerate(lines, start=1). Распаковка разбирает пару на две переменные, а start=1 делает номера человеческими — первая строка получит номер 1.
Урок 4: enumerateКак посчитать, сколько раз каждое слово встретилось в тексте?
Циклом по словам и счётчиком в словаре: counts[w] = counts.get(w, 0) + 1. Ключи в словаре стоят в порядке первого появления. В рабочем коде то же делает Counter из курса словарей, но цикл стоит написать руками хотя бы раз.
Курс словарейКак разделить строку по запятой и не получить лишних пустых элементов?
split(',') режет по запятым, и между соседними запятыми остаётся пустой кусок. Чистят его фильтром: [p for p in parts if p]. Заодно помогает strip() — он срезает пробелы с краёв, чтобы в словарь не попадали ключи вроде ' a'.
Как посчитать буквы в строке, не считая пробелы и знаки?
Циклом по символам с проверкой isalpha(): счётчик растёт на каждый символ, для которого ch.isalpha() истинно. Для цифр есть isdigit(), для знаков препинания — ispunctuation().
Понравился урок? Сошлитесь на него
«Цикл по строке — это цикл по её символам, а разбор текста начинается со split: строка превращается в список слов.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Циклы · Урок 3
Python цикл по строке, словарю и строкам файла
for ходит не только по спискам: строка — последовательность символов, словарь перебирается по ключам, а items отдаёт готовые пары. Плюс построчный перебор текста файла.
Циклы · Урок 4
enumerate в Python: индекс и значение вместе
Нужен номер элемента вместе с самим элементом? enumerate отдаёт циклу пары «индекс — значение»: без ручного счётчика и с нумерацией с единицы через start=1.
Циклы · Урок 11
Счётчики и аккумуляторы в циклах Python
Сумма чека, число совпадений, лучший результат: переменная, объявленная до цикла и копящая значения внутри, — приём старше языков. Разбираем счётчики, суммы, максимумы и их ловушки.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Функции · Урок 20
Проект на функциях Python: библиотека утилит для текста
Итоговый проект раздела: своя мини-библиотека утилит для текста — normalize, word_count, top_words. Три куска, каждый запускается и проверяется отдельно.
python normalize строкиpython подсчёт слов в строке
Словари · Урок 20
Проект: частотный словарь текста
Финальный проект: частотный словарь текста — режем текст на слова, чистим, отбрасываем стоп-слова, считаем через Counter и выводим топ-5 ровными колонками.
подсчёт слов pythonпосчитать слова в тексте python
Циклы · Урок 1
Цикл for в Python: первый цикл
Первый цикл for: компьютер повторяет одну строку за вас. Перебираем список, разбираем переменную цикла и тело с отступами — и видим, зачем цикл вместо копипасты.
цикл for pythonpython цикл for