Работа с текст
Проблем
Кодът е верен, а не минава
Магазинът дава 10% отстъпка с код SUMMER10. Клиентът го преписва от рекламата, но пише с малки букви и случайно слага интервал отпред:
code = input()if code == "SUMMER10": print("Отстъпка 10%")else: print("Невалиден код") summer10Невалиден кодЗа човек кодът е същият. За програмата summer10 и SUMMER10 са различни текстове: първият има един символ повече, а буквите са други. Трябва да можеш да гледаш вътре в текста и да го оправяш.
Идеята
Текстът е поредица от символи
Текстът е подредени един след друг символи: букви, цифри, интервали, знаци. Всеки символ има индекс, като в масив. Първият е с индекс 0.
code = "SUMMER10"print(len(code))print(code[0])print(code[len(code) - 1])8S0len(code)е броят на символите.code[0]е символът с индекс 0. Последният символ е с индексlen(code) - 1.
Отделен тип за един символ (в Java и C# се казва char) тук няма. Символът е просто текст с дължина 1. Единичните и двойните кавички правят едно и също: 'S' и "S" са еднакви текстове.
code = "SUMMER10"print(code[-1])print(type(code[0]))print(len(code[0]))print('S' == "S")0<class 'str'>1Truecode[-1] е последният символ: отрицателният индекс брои отзад, -1 е последният, -2 предпоследният. Това е по-кратко от code[len(code) - 1].
len дава дължината и на текста, и на списъка.
Виж го
Символ по символ
Колко цифри има в телефонния номер? Минаваш с цикъл през индексите от 0 до последния и гледаш всеки символ:
phone = "0888 123 456"digits = 0for i in range(len(phone)): c = phone[i] if c >= "0" and c <= "9": digits += 1print(f"Цифри: {digits}")Цифри: 10c >= "0" and c <= "9" работи, защото всеки символ има код: число в таблицата със символите. Текстовете се сравняват по кодовете на символите. Цифрите от "0" до "9" имат поредни кодове, буквите от "a" до "z" също.
По-точно, за любопитните
- За такива проверки има готови методи:
c.isdigit(),c.isalpha(),c.isupper(),c.islower(). Те знаят и кирилицата. - Кодът на символ дава
ord("A"), тоест 65. Обратно,chr(66)е"B". Текст и число не се събират:"a" + 1спира програмата сTypeError. - Без индекс:
for c in phone:минава направо през символите на текста.
print("7".isdigit(), "ж".isalpha(), "Ж".isupper(), "ж".islower())print(ord("A"), chr(66))try: print("a" + 1)except TypeError as e: print(f"TypeError: {e}")digits = 0for c in "0888 123 456": if c.isdigit(): digits += 1print(digits)True True True True65 BTypeError: can only concatenate str (not "int") to str10Пробвай
Кой символ?
Какво ще отпечата програмата?
word = "Поръчка"print(word[3])print(len(word))Индексите са П 0, о 1, р 2, ъ 3. Символът с индекс 3 е четвъртият: „ъ“. Дължината е броят на всички символи, 7. Последният индекс е 6.
Идеята
Методите на текста
Текстът идва с готови методи: действия, които викаш с точка след текста. Ето поправката на промо кода:
code = " summer10"clean = code.strip().upper()print(f"[{clean}]")print(clean == "SUMMER10")[SUMMER10]Truestrip() маха интервалите отпред и отзад. upper() прави всички букви главни. Методите се нареждат един след друг: първият връща текст и върху него се вика вторият.
Още няколко, върху имейл адрес:
email = "ivan.petrov@mail.bg"print("@" in email)print(email.find("@"))print(email[0:email.find("@")])print(email.replace(".", " "))print(email.endswith(".bg"))True11ivan.petrovivan petrov@mail bgTrue| Метод | Какво прави |
|---|---|
x in email |
има ли го x вътре |
find(x) |
на кой индекс е x за първи път (-1, ако го няма) |
email[a:b] |
част от текста |
replace(x, y) |
всяко x се заменя с y |
startswith(x), endswith(x) |
започва ли (свършва ли) с x |
lower() |
всички букви малки |
"@" in email не е метод, а оператор: in пита дали текстът вляво се среща в текста вдясно. Частта от текста се взима с квадратни скоби и двоеточие, email[a:b], за нея има повече в „По-точно“ отдолу.
print("ivan.petrov@mail.bg".find("#"))print("Кафе".startswith("К"))print("Кафе".lower())-1TrueкафеПо-точно, за любопитните
date[a:b] взима символите от индекс a до индекс b, без b. Броят им е b - a. Без край, date[a:], взима всичко до края. Отрицателният индекс брои отзад: date[-2:] са последните два символа.
date = "2026-10-24"print(date[5:7])print(date[8:])print(date[-2:])102424Идеята
Текстът не се променя
Има една особеност, която обърква всички в началото:
name = "мария"name.upper()print(name)name = name.upper()print(name)марияМАРИЯВторият ред не прави нищо видимо. upper() не променя name. Той прави нов текст с главни букви и го връща. Никой не го записва и той се губи.
Веднъж създаден, текстът не може да се промени. Казва се, че е неизменим (immutable). Всеки метод, който „променя“ текст, всъщност връща нов. За да го запазиш, присвояваш: name = name.upper().
name = "мария"name.upper()print(name)name = name.upper()print(name)Стъпка по стъпка, с думи
- В name е текстът „мария“: 5 символа с индекси от 0 до 4.
- upper() не пипа „мария“. Прави нов текст „МАРИЯ“.
- Никой не записва новия текст и той се губи.
- В name си е „мария“ и то се отпечатва.
- Пак нов текст „МАРИЯ“, но сега = го записва в name. Старото „мария“ отпада.
- Сега в name е „МАРИЯ“.
По-точно, за любопитните
- Символ вътре в текста не може да се смени и с индекс:
name[0] = "М"спира програмата сTypeError: 'str' object does not support item assignment. Правиш нов текст, например"М" + name[1:]. - Когато имаш много парчета, събери ги в списък и ги долепи наведнъж с
join:
parts = ["мляко", "хляб", "яйца"]print(", ".join(parts))мляко, хляб, яйцаПробвай
Намери грешката
Потребителят въвежда имейла си с главни букви и интервали. Програмата трябва да го изчисти и да го пусне, но казва „Няма такъв потребител.“. На кой ред е грешката?
Избери реда с грешката.
email.strip() връща нов текст без интервалите, но той не се записва никъде. email си остава с интервалите. Поправката е email = email.strip(), както на ред 2.
Идеята
Текстът на части
Често текстът съдържа няколко неща, разделени със знак: продукти със запетая, думи с интервал. split го разделя на части и връща списък от текстове:
shopping = "мляко,хляб,яйца,сирене"items = shopping.split(",")print(f"Продукти: {len(items)}")for i in range(len(items)): print(f"{i + 1}. {items[i]}")Продукти: 41. мляко2. хляб3. яйца4. сиренеРазделителят не влиза в частите. Оттук нататък работиш с обикновен списък: дължина, индекси, цикъл.
Така се чете и цял ред числа от клавиатурата: разделяш го и превръщаш всяка част в число. Точно това ти липсваше в миналия урок за таблиците:
parts = input().split(" ")total = 0for p in parts: total += int(p)print(total)42 38 51 47 60238По-точно, за любопитните
- Два интервала един до друг дават празна част
''между тях.split()без аргумент разделя по всякакви интервали и не дава празни части, а пропуска и интервалите отпред и отзад. - Обратното на
splitе", ".join(items): долепва частите с разделител.
print("а б".split(" "))print(" а б ".split())print(", ".join(["а", "б"]))['а', '', 'б']['а', 'б']а, бПробвай
Едно и също ли е?
В Python == сравнява съдържанието на текстовете, буква по буква. Но главната и малката буква са различни символи. Въведено е София:
Какво ще отпечата програмата?
city = input()print(city == "София")print(city == "софия")print(city.lower() == "софия")city == "София" е True: буквите са същите. "софия" започва с малко „с“, а то е друг символ, затова е False. Ако главните и малките букви нямат значение, сравни двата текста с малки букви: city.lower() == "софия".
По-точно, за любопитните
Има и оператор is. Той не сравнява буквите, а пита дали двете страни са един и същ обект в паметта. Текстът, прочетен от клавиатурата, е нов обект, затова при вход admin е така:
user = input()print(user is "admin")print(user == "admin")FalseTrueТекст сравнявай винаги с ==.
Упражнение
Имена и думи
Реши задачите в редактора си. Текстът се чете от клавиатурата като цял ред.
1. Името наобратно. Прочети име и го отпечатай отзад напред. Минаваш през индексите от последния към 0 и долепваш символите в нов текст.
МарияяираМ2. Брой думи. Прочети изречение и преброй думите. Между думите може да има повече от един интервал, а в началото и в края може да има интервали. Подсказка: дума започва там, където символът не е интервал, а предният е интервал (или няма преден).
Днес е хубав денДуми: 43. Палиндром. Палиндромът се чете еднакво отпред назад и отзад напред. Интервалите и главните букви не се броят. Махни интервалите, направи буквите малки и сравни първия символ с последния, втория с предпоследния и т.н.
Аз обичам мач и бозаПалиндром еКафе с млякоНе е палиндромУпражнение
Проверки и броене
4. Сигурна парола. Питай за парола, докато не въведат сигурна: поне 8 знака, поне една цифра, една главна и една малка буква. След всяка слаба парола кажи какво се иска. Подсказка: while True с break, когато паролата е сигурна, и проверка на всеки символ с isdigit, isupper, islower.
kafekafe2026Kafe2026Парола:Слаба парола: поне 8 знака, цифра, главна и малка буква.Парола:Слаба парола: поне 8 знака, цифра, главна и малка буква.Парола:Паролата е приета.Още задачи
- Запетаи вместо интервали. Прочети изречение и замени всеки интервал със запетая.
Утре заминаваме за Варна→Утре,заминаваме,за,Варна. - Най-дългото име. Прочети имена, разделени със запетая, и отпечатай най-дългото.
Ана,Кристина,Петър→Кристина. - Гласните със звездичка. Замени всяка гласна (а, ъ, о, у, е, и) със
*, независимо дали е главна или малка.Обичам кафе→*б*ч*м к*ф*. - Честота на буквите. Преброй колко пъти се среща всяка буква в текста, без значение главна или малка. Подсказка: списък с 32 брояча, по един за всеки символ от
'а'до'я'(в таблицата със символите между тях има и две руски букви, ы и э, техните броячи просто остават 0). Индексът на букватаcеord(c) - ord("а"). Отпечатай само буквите, които се срещат. - Графика на символите. Като горната задача, но вместо числото отпечатай толкова звездички:
а: ****. - Колко пъти всяка дума. Прочети изречение и за всяка различна дума отпечатай колко пъти се среща. Подсказка: раздели на думи и за всяка дума провери дали вече не е броена по-рано в списъка.
- Сортиране по дължина. Прочети думи, разделени с интервал, и ги отпечатай от най-късата към най-дългата. Сортирай списъка както сортираше числа, но сравнявай дължините.
- Брой изречения. Преброй изреченията в текст: всяко свършва с
.,!или?. Внимавай с...и?!: те завършват едно изречение, не три. - Балансирани скоби. Провери дали скобите в текста са балансирани. С един вид скоби стига брояч:
(добавя 1,)вади 1. Броячът не бива да пада под 0 и накрая трябва да е 0. С три вида,(),[],{}, ти трябва списък от символи, в който пазиш отворените скоби, и брояч докъде е пълен: при затваряща скоба последната отворена трябва да е от същия вид.{[()]}е балансиран,([)]не е.
Тест