Три рівні. Кожен наступний спирається на попередній, але братися можна за будь-який.
Пиши в окремому файлі homework_05.py або в новому зошиті — головне, щоб код
запускався й друкував результат.
З бібліотек не потрібно нічого: усе робиться вбудованими можливостями рядка.
Єдиний виняток — unicodedata у завданні 3.2, і то лише для перевірки.
рівень 1Рівень 1 — База
1.1 · Розбір «брудного» запису
Дано рядок, у якому поля розділені крапкою з комою, а навколо кожного — випадкові пробіли:
сирий = " Львів ; чай зелений ; 1250.00 ; 2 "
Розбери його на чотири значення: місто (рядок), товар (рядок), ціна (float)
і кількість (int). Кожне поле мусить бути очищене від пробілів з обох боків.
Надрукуй усі чотири по одному в рядок разом із типом.
Зроблено, якщо: виконуються всі чотири перевірки
assert місто == "Львів"
assert товар == "чай зелений" # пробіл ВСЕРЕДИНІ має лишитися
assert ціна == 1250.0 and isinstance(ціна, float)
assert кількість == 2 and isinstance(кількість, int)
Пильнуй за третім рядком:
.strip()знімає пробіли лише з країв. Якщо в тебе вийшло"чайзелений"— ти десь застосував.replace(" ", ""), а це вже інша операція.
1.2 · Символи проти байтів
Для тих самих чотирьох полів надрукуй таблицю: поле, len() у символах,
len(поле.encode()) у байтах і різницю між ними.
Зроблено, якщо: твій код друкує таблицю, з якої видно, що різниця дорівнює кількості кириличних літер у полі, і виконується
assert len("Львів") == 5
assert len("Львів".encode()) == 10
assert len("1250.00") == len("1250.00".encode()) # чиста ASCII — байт у байт
рівень 2Рівень 2 — Плюс
2.1 · Рядок чека фіксованої ширини
Склади однорядковий чек рівно 46 символів завширшки:
- назва товару притиснута ліворуч;
- сума (
ціна * кількість) притиснута праворуч, з двома знаками після коми й роздільником тисяч; - проміжок між ними заповнений крапками.
Для ("чай зелений", 2, 1250.00) має вийти:
чай зелений...........................2,500.00
Зроби це однією f-специфікацією для проміжку — тобто спершу порахуй, скільки символів лишилось під крапки, а потім скористайся заповнювачем у міні-мові формату.
Зроблено, якщо:
assert len(чек) == 46
assert чек.startswith("чай зелений")
assert чек.endswith("2,500.00")
assert чек.count(".") == 27 + 1 # 27 крапок-заповнювачів плюс десяткова
Перевір також на довгій назві: якщо назва разом із сумою вже займає 46 символів і більше, рядок не має обрізатись — просто вийде довшим. Поясни в коментарі одним реченням, чому це так.
2.2 · Скільки коштує неохайність
Візьми той самий сирий рядок із завдання 1.1 і не роби .strip().
Розбий його по ";" і надрукуй порівняння: для кожного поля покажи
repr(поле), поле == очікуване і поле.strip() == очікуване.
Зроблено, якщо: у виводі чітко видно, що без .strip() жодне з чотирьох
порівнянь не спрацювало, і виконується
assert поля_без_strip[0] != "Львів"
assert поля_без_strip[0].strip() == "Львів"
І окремо: поясни двома реченнями, чому помилка такого роду найдорожча —
дані виглядають правильними на екрані, а порівняння дає False.
рівень 3Рівень 3 — Виклик
3.1 · Розвертання слів без циклів і без reversed
Напиши функцію розвернути_слова(текст), яка розвертає порядок слів,
не розвертаючи самих слів:
розвернути_слова("кава мелена холодна") # -> "холодна мелена кава"
Дозволено лише: .split(), зрізи (у тому числі [::-1]), .join().
Заборонено: for, while, reversed, list.reverse, sorted.
Зроблено, якщо: виконуються всі чотири перевірки
assert розвернути_слова("кава мелена холодна") == "холодна мелена кава"
assert розвернути_слова("одне") == "одне"
assert розвернути_слова(" зайві пробіли ") == "пробіли зайві"
assert розвернути_слова("") == ""
Третя перевірка не випадкова: вона проходить лише тоді, коли ти взяв
.split()без аргументу. З аргументом" "там з'являться порожні рядки.
3.2 · Свій casefold для української
Порівняння рядків без урахування регістру виглядає просто, поки не з'явиться
ß. Досліди межу застосовності на конкретних прикладах.
Напиши функцію однакові_без_регістру(a, b), яка повертає True, якщо рядки
збігаються з точністю до регістру. Перевір її на п'яти парах і склади таблицю:
пара, результат через .lower(), результат через .casefold(), і чи вони
розійшлись.
Обов'язкові пари:
("Київ", "КИЇВ") # тут усе нудно й правильно
("Straße", "STRASSE") # німецька ß
("file", "file") # типографська лігатура fi — один символ!
("Σ", "ς") # грецька сигма: велика одна, малих дві
("İstanbul", "istanbul") # турецька І з крапкою
Зроблено, якщо: у таблиці видно рівно три пари, де .lower()
і .casefold() дають різні відповіді, і ти назвав ту єдину пару, де
обидва способи однаково помиляються. Поясни двома-трьома реченнями,
чому «зробити маленькими й порівняти» — це не універсальне правило.
Для перевірки, що саме сталося з символом, стане в пригоді:
import unicodedata
print(unicodedata.name("ß"), "->", [unicodedata.name(c) for c in "ß".upper()])
3.3 · Скільки насправді коштує +=
Не міряй час — він залежить від машини. Порахуй роботу: напиши функцію
скопійовано_символів(n, L), яка повертає, скільки символів скопіює
результат += шматок на n кроках при довжині шматка L.
Зроби це двома способами: покроковим підрахунком і замкненою формулою.
Зроблено, якщо: обидва способи збігаються на всіх значеннях, і виконуються
assert скопійовано_формулою(1, 6) == 6
assert скопійовано_формулою(60, 6) == 10980
assert скопійовано_формулою(1000, 6) == 3_003_000
assert скопійовано_кроками(60, 6) == скопійовано_формулою(60, 6)
Додатково: порахуй, у скільки разів це більше за join при n = 10_000,
і напиши одним реченням, що саме росте — кількість об'єктів чи обсяг копіювання.
Підказки
- Заповнювач у міні-мові формату йде першим. Специфікація
.<20означає «ширина 20, притиснути ліворуч, доповнити крапками». Ширину можна підставити виразом:f"{назва:.<{скільки}}"— фігурні дужки всередині специфікації теж працюють. - У 2.1 рахуй з кінця. Спершу відформатуй суму (вона має фіксований вигляд), подивись її довжину, а вже потім вирахуй, скільки лишилось під назву й крапки.
- У 3.1 порядок дій має значення. Розверни список слів, а не рядок:
текст.split()дає список, а до списку теж можна застосувати[::-1]— зрізи працюють не лише з рядками (це буде тема 06). - У 3.2 не вгадуй, а друкуй. Для кожного символу подивись, у що він
перетворюється:
"ß".lower(),"ß".upper(),"ß".casefold()— три різні відповіді, і саме на цьому все й ламається. - У 3.3 не будуй справжніх рядків. Тобі потрібне лише число скопійованих
символів; довжина проміжного результату після
k-го кроку — цеk * L, і рівно стільки символів копіюється на наступному кроці.