Українська
Практика
Приклад 1. Навчальний шифр Цезаря
Написати програму, яка зсуває українські літери на задану кількість позицій в алфавіті, зберігає регістр і не змінює пробіли та пунктуацію. Після шифрування виконати зворотне перетворення. Це навчальна підстановка символів, непридатна для захисту секретних даних.
py
ALPHABET = "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя"
def caesar(text: str, shift: int) -> str:
shift %= len(ALPHABET)
rotated = ALPHABET[shift:] + ALPHABET[:shift]
source = ALPHABET + ALPHABET.upper()
target = rotated + rotated.upper()
return text.translate(str.maketrans(source, target))
def main() -> None:
text = "АБВ, Ґанок!"
encoded = caesar(text, 1)
print(encoded)
print(caesar(encoded, -1))
print(caesar(text, 33) == text)
if __name__ == "__main__":
main()Результат:
БВГ, Дбопл!
АБВ, Ґанок!
TrueЗалишок від ділення переводить зсув у діапазон індексів алфавіту. Таблиця містить і малі, і великі літери; символів поза таблицею метод translate не змінює. Перевірте порожній рядок, від’ємний зсув, зсув на 33 та останню літеру «я». Властивість caesar(caesar(text, k), -k) == text має виконуватися для кожного такого тесту. Якщо введення містить декомпоновані літери, спочатку узгодьте правило нормалізації NFC.
Приклад 2. Перевірка навчальної політики пароля
Написати програму, яка перевіряє задані рядки за навчальним правилом: довжина 8–32 символи; лише ASCII-літери, цифри та !@#$%; є хоча б одна велика літера, мала літера, цифра і спеціальний символ. Пояснити кожне порушення. Це вправа на regex, а не оцінювання реальної стійкості пароля. Справжні паролі для демонстрації не вводять.
py
import re
ALLOWED = r"[A-Za-z0-9!@#$%]{8,32}"
POLICY = re.compile(
r"(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%])"
+ ALLOWED
)
def violations(text: str) -> list[str]:
errors = []
if not 8 <= len(text) <= 32:
errors.append("довжина поза діапазоном 8–32")
if re.fullmatch(r"[A-Za-z0-9!@#$%]*", text) is None:
errors.append("є недозволені символи")
checks = [(r"[a-z]", "немає малої літери"),
(r"[A-Z]", "немає великої літери"),
(r"[0-9]", "немає цифри"),
(r"[!@#$%]", "немає спеціального символу")]
for pattern, message in checks:
if re.search(pattern, text) is None:
errors.append(message)
return errors
def main() -> None:
samples = ["Abcdef1!", "abcdef12", "Abcdef1!\n"]
for number, text in enumerate(samples, start=1):
errors = violations(text)
assert (POLICY.fullmatch(text) is not None) == (not errors)
result = "; ".join(errors) if errors else "правила виконані"
print(f"Тест {number}: {result}")
if __name__ == "__main__":
main()Результат:
Тест 1: правила виконані
Тест 2: немає великої літери; немає спеціального символу
Тест 3: є недозволені символиПерегляди вперед лише перевіряють наявність потрібних класів; основний клас символів і fullmatch задають дозволену довжину та відсутність зайвого хвоста. Окрема функція повертає пояснення, які один логічний результат regex не містить. assert порівнює два способи перевірки під час розроблення; він не замінює валідацію введення, бо може бути вимкнений режимом -O.
Для граничних перевірок додайте рядки довжини 7, 8, 32, 33, кириличну літеру, табуляцію та порожній рядок. У застосунку з довільним введенням спочатку обмежте його довжину, а потім виконуйте пошук. Не записуйте введений секрет у повідомлення про помилку або журнал – достатньо номера тесту й причини.
Приклад 3. Дати й суми в тексті чеку
Написати програму, яка знаходить дати DD.MM.YYYY, замінює дійсні дати на ISO-формат YYYY-MM-DD, а недійсні залишає незмінними. Знайти невід’ємні суми виду 12,50 грн та обчислити підсумок у цілих копійках. У цьому навчальному форматі перед числом не може стояти мінус, цифра, крапка або кома.
py
import re
from datetime import date
DATES = re.compile(r"\b([0-9]{2})\.([0-9]{2})\.([0-9]{4})\b")
MONEY = re.compile(r"(?<![\d.,-])([0-9]+),([0-9]{2}) грн\b")
def iso_date(match: re.Match[str]) -> str:
day, month, year = map(int, match.groups())
try:
return date(year, month, day).isoformat()
except ValueError:
return match.group()
def main() -> None:
text = "Чек 17.09.2026: 12,50 грн; 7,25 грн. 31.02.2026"
print(DATES.sub(iso_date, text))
amounts = MONEY.findall(text)
total = sum(int(uah) * 100 + int(kop) for uah, kop in amounts)
print(f"Позицій: {len(amounts)}")
print(f"Разом: {total // 100},{total % 100:02d} грн")
if __name__ == "__main__":
main()Результат:
Чек 2026-09-17: 12,50 грн; 7,25 грн. 31.02.2026
Позицій: 2
Разом: 19,75 грнРегулярний вираз виділяє структуру дати, а date перевіряє календар. Функція-замінник повертає початковий збіг, якщо дата недійсна. У промисловому імпорті така дата потребувала б окремого повідомлення, але контракт цього прикладу зберігає її для ручної перевірки. Копійки рахуємо цілими числами, тому похибка float не накопичується. Перевірте високосний день, нульовий місяць, суму 0,00 грн, відсутність сум і неправильну кількість копійок.