Рядки трапляються дитині раніше за будь-які інші дані: перша ж програма щось друкує, друга щось запитує. Але працювати з ними всерйоз починають пізніше, і тоді з'ясовується, що рядок уміє значно більше, ніж просто виводитися на екран.
Нижче довідник по тому, що справді використовується: як дістати частину рядка, які методи потрібні в задачах, як зібрати текст із чисел і чому спроба змінити одну букву закінчується помилкою. Приклади короткі — їх зручно набрати й одразу подивитися результат.
Рядок — це послідовність
До кожного символу можна звернутися за номером, так само як до елемента списку. Нумерація з нуля, від'ємні номери рахуються з кінця.
slovo = 'Python'
print(slovo[0]) # P
print(slovo[-1]) # n
print(slovo[1:4]) # yth
print(slovo[::-1]) # nohtyP
print(len(slovo)) # 6
Зрізи працюють так само, як у списках: права межа не входить, тому [1:4] дає три символи. Запис [::-1] перевертає рядок — найкоротший спосіб перевірити, чи є слово паліндромом, і один з перших трюків, який діти переписують один в одного.
Методи, які потрібні насправді
| Метод | Що робить | Приклад результату |
|---|---|---|
upper() | усі великі | PYTHON |
lower() | усі малі | python |
capitalize() | перша велика | Python |
strip() | прибирає пробіли по краях | текст без відступів |
replace(a, b) | замінює всі входження | новий рядок |
split() | ріже на список слів | список |
join(spysok) | склеює список у рядок | рядок |
find(a) | номер символу або -1 | число |
count(a) | скільки разів зустрілося | число |
startswith(a) | чи починається з | True або False |
isdigit() | чи складається з цифр | True або False |
Два останні рядки корисніші, ніж здаються. Перевірка isdigit() дозволяє запитати в користувача число і не впасти, якщо він ввів слово: спочатку перевіряємо, потім перетворюємо. Без неї перша ж програма з вводом падає, щойно хтось натисне Enter не ту клавішу.
Метод find() відрізняється від схожого index() однією деталлю: коли нічого не знайдено, перший тихо повертає мінус одиницю, а другий зупиняє програму помилкою. Для перевірки «чи є таке взагалі» надійніше взяти in: запис 'a' in slovo читається краще за обидва.
f-рядки: складання тексту з чисел
Найзручніший спосіб зібрати повідомлення — поставити перед лапками літеру f і вписати змінні прямо в текст, у фігурних дужках.
imia = 'Olia'
ochky = 120
print(f'{imia} набрала {ochky} балів')
print(f'Середнє: {ochky / 7:.2f}')
Другий рядок показує заодно форматування: двокрапка й .2f означають «показати два знаки після коми». Без цього ділення дає довгий хвіст цифр, який у звіті виглядає неохайно.
До f-рядків текст збирали плюсом, і цей спосіб досі зустрічається в старих підручниках. Проблема в тому, що плюс не вміє складати текст із числом: 'Балів: ' + 120 дає помилку, і доводиться писати str(120) навколо кожного числа. З f-рядком перетворення відбувається само.
Рядок не можна змінити
Ось головна несподіванка теми. Спроба замінити один символ на місці не працює взагалі:
slovo = 'Python'
slovo[0] = 'J' # помилка
slovo = 'J' + slovo[1:] # а так правильно
Рядки в Python незмінні: будь-який метод не править наявний, а повертає новий. Тому запис slovo.upper() сам по собі нічого не змінює — результат треба кудись покласти, хоча б назад у ту саму змінну. Це найчастіша причина, через яку «метод не спрацював»: він спрацював, просто результат нікуди не записали.
Списки в цьому влаштовані навпаки, і дитині корисно побачити обидва випадки поруч: тоді правило запам'ятовується як відмінність, а не як окремий факт про рядки.
input завжди дає текст
Ще одне місце, де програма падає на рівному місці. Усе, що введено з клавіатури, приходить рядком, навіть якщо це цифри.
vik = input('Скільки тобі років? ')
print(vik + 1) # помилка
print(int(vik) + 1) # працює
Перетворення int() потрібне кожного разу, коли введене збираються рахувати. Якщо число дробове, береться float(). А якщо користувач ввів слово, int() теж падає — і саме тут стає в пригоді згаданий вище isdigit().
Перебір рядка циклом
Рядок перебирається так само, як список, і це той момент, коли дві теми нарешті сходяться. Цикл проходить по символах, а не по словах, і цього вистачає для більшості навчальних задач.
slovo = 'programuvannia'
holosni = 'aeiouyаеєиіїоуюя'
lichylnyk = 0
for bukva in slovo:
if bukva in holosni:
lichylnyk = lichylnyk + 1
print(lichylnyk)
Задача про підрахунок голосних виглядає шкільною, але всередині неї три важливі речі одразу: перебір, перевірка на входження і накопичувач. Тому ми ставимо її в програму саме після рядків — вона збирає докупи те, що доти існувало окремо.
Якщо потрібен не сам символ, а його номер, зручніше enumerate: він віддає пару «номер і символ» за один прохід, і не доводиться вести окрему змінну-лічильник.
Довгий текст і перенос рядка
Для багаторядкового тексту беруть три лапки замість одної. Усе, що всередині, зберігається як є, разом з переносами:
pravyla = '''Правила гри:
1. Три спроби
2. Підказка коштує бал'''
print(pravyla)
Другий спосіб — спеціальна пара символів усередині звичайного рядка, яка означає перехід на новий рядок. Виглядає вона як зворотна скісна риска з буквою n, і саме через неї найчастіше виникає плутанина: у тексті її видно двома символами, а на екрані вона перетворюється на перенос.
Для дитини корисно одразу пояснити, що це не помилка друку, а команда всередині тексту. Поруч живуть ще дві такі ж: табуляція і сама зворотна скісна риска, яку, щоб надрукувати, доводиться писати двічі.
split і join: туди й назад
Ці два методи ходять парою і разом вирішують більшість задач з текстом. Перший розрізає рядок на список, другий збирає список назад у рядок.
rechennia = 'kit sydyt na vikni'
slova = rechennia.split() # список з чотирьох слів
print(len(slova)) # 4
print(' '.join(slova[::-1])) # слова у зворотному порядку
Без аргументів split() ріже по будь-яких пробілах, і зайві пробіли між словами його не бентежать. Можна вказати, по чому різати: split(',') розбере рядок з комами, і саме так читають прості таблиці.
Запис ' '.join(slova) спочатку виглядає перевернутим: роздільник стоїть попереду, а список у дужках. Логіка в тому, що склеює саме роздільник, і це той рідкісний випадок, коли пояснення «так вирішили» працює гірше, ніж просто запам'ятати форму.
Одна задача цілком
Щоб методи перестали бути переліком, корисно скласти з них щось робоче. Класична задача — порахувати, скільки разів кожне слово зустрічається в тексті. Вона коротка, і в ній працює все одразу: приведення регістру, різання на слова, словник як накопичувач.
tekst = 'Kit sydyt. Kit spyt. Sobaka bihaie.'
slova = tekst.lower().replace('.', ' ').split()
chastota = {}
for slovo in slova:
chastota[slovo] = chastota.get(slovo, 0) + 1
print(chastota)
Другий рядок варто розібрати окремо: методи викликаються ланцюжком, зліва направо. Спочатку все стає малими літерами, потім крапки замінюються пробілами, і тільки після цього рядок ріжеться на слова. Поміняти порядок — і крапка приклеїться до слова, а kit і Kit порахуються як різні.
Саме тут видно, навіщо був потрібен get зі словників: без нього перше ж нове слово зупинило б програму помилкою.
Три помилки, які повторюються
Перша: slovo.replace('a', 'o') написано окремим рядком, а результат нікуди не збережено. Виглядає як «метод не працює».
Друга: порівняння з різним регістром. Рядок 'Так' не дорівнює 'так', і вікторина не зараховує правильну відповідь. Лікується приведенням обох сторін до нижнього регістру перед порівнянням.
Третя: невидимі пробіли. Відповідь, скопійована з іншого місця, часто приходить з пробілом на кінці, і порівняння провалюється без видимої причини. Звичка писати .strip() одразу після input() знімає цю проблему назавжди.
Рядки добре лягають поруч зі списками — їх довідник тут, а перебирати і те, і те зручно циклом for. Що ламається в перших програмах найчастіше, зібрано в типових помилках новачків.