Skip to content
wannacode

Working with text

Problem

The code is right, but it does not work

The shop gives 10% off with the code SUMMER10. A customer copies it from the ad, but types it in lowercase and puts a space in front by accident:

code = input()
if code == "SUMMER10":
print("10% off")
else:
print("Invalid code")
Input
summer10
Output
Invalid code

To a person, the code is the same. To the program, summer10 and SUMMER10 are different texts: the first has one more character, and the letters are different. You need to be able to look inside a text and fix it.

The idea

Text is a sequence of characters

Text is characters placed one after another: letters, digits, spaces, signs. Each character has an index, like in an array. The first one has index 0.

code = "SUMMER10"
print(len(code))
print(code[0])
print(code[len(code) - 1])
Output
8
S
0
  • len(code) is the number of characters.
  • code[0] is the character with index 0. The last character has index len(code) - 1.

There is no separate type for a single character here (in Java and C# it is called char). A character is simply a text of length 1. Single and double quotes do the same thing: 'S' and "S" are the same text.

code = "SUMMER10"
print(code[-1])
print(type(code[0]))
print(len(code[0]))
print('S' == "S")
Output
0
<class 'str'>
1
True

code[-1] is the last character: a negative index counts from the back, -1 is the last one, -2 the one before it. This is shorter than code[len(code) - 1].

len gives the length of both text and lists.

See it

Character by character

How many digits are in the phone number? You loop through the indexes from 0 to the last one and look at each character:

phone = "0888 123 456"
digits = 0
for i in range(len(phone)):
c = phone[i]
if c >= "0" and c <= "9":
digits += 1
print(f"Digits: {digits}")
Output
Digits: 10

c >= "0" and c <= "9" works because every character has a code: a number in the character table. Texts are compared by the codes of their characters. The digits from "0" to "9" have consecutive codes, and so do the letters from "a" to "z".

More precisely, if you are curious
  • There are ready-made methods for checks like these: c.isdigit(), c.isalpha(), c.isupper(), c.islower(). They also know letters outside English, like é.
  • ord("A") gives the code of a character, that is, 65. The other way, chr(66) is "B". Text and a number don't add up: "a" + 1 stops the program with TypeError.
  • Without an index: for c in phone: goes straight through the characters of the text.
print("7".isdigit(), "é".isalpha(), "É".isupper(), "é".islower())
print(ord("A"), chr(66))
try:
print("a" + 1)
except TypeError as e:
print(f"TypeError: {e}")
digits = 0
for c in "0888 123 456":
if c.isdigit():
digits += 1
print(digits)
Output
True True True True
65 B
TypeError: can only concatenate str (not "int") to str
10

Try it

Which character?

What will the program print?

word = "Invoice"
print(word[3])
print(len(word))
Answer

The idea

The methods of text

Text comes with ready-made methods: actions you call with a dot after the text. Here is the fix for the promo code:

code = " summer10"
clean = code.strip().upper()
print(f"[{clean}]")
print(clean == "SUMMER10")
Output
[SUMMER10]
True

strip() removes the spaces at the front and at the back. upper() makes all the letters uppercase. Methods can be chained one after another: the first returns a text, and the second is called on it.

A few more, on an email address:

email = "ivan.petrov@mail.bg"
print("@" in email)
print(email.find("@"))
print(email[0:email.find("@")])
print(email.replace(".", " "))
print(email.endswith(".bg"))
Output
True
11
ivan.petrov
ivan petrov@mail bg
True
Method What it does
x in email whether x is inside
find(x) the index where x first appears (-1 if it is not there)
email[a:b] a part of the text
replace(x, y) every x is replaced with y
startswith(x), endswith(x) whether it starts (ends) with x
lower() all letters lowercase

"@" in email is not a method but an operator: in asks whether the text on the left appears in the text on the right. You take a part of the text with square brackets and a colon, email[a:b]; there is more on that in "More precisely" below.

print("ivan.petrov@mail.bg".find("#"))
print("Cafe".startswith("C"))
print("Cafe".lower())
Output
-1
True
cafe
More precisely, if you are curious

date[a:b] takes the characters from index a to index b, without b. Their count is b - a. Without an end, date[a:], it takes everything to the end. A negative index counts from the back: date[-2:] is the last two characters.

date = "2026-10-24"
print(date[5:7])
print(date[8:])
print(date[-2:])
Output
10
24
24

The idea

Text does not change

There is one quirk that confuses everyone at first:

name = "maria"
name.upper()
print(name)
name = name.upper()
print(name)
Output
maria
MARIA

The second line does nothing you can see. upper() does not change name. It makes a new text in uppercase and returns it. Nobody stores it, and it is lost.

Once created, a text cannot be changed. It is called immutable. Every method that "changes" a text actually returns a new one. To keep it, you assign it: name = name.upper().

name = "maria"
name.upper()
print(name)
name = name.upper()
print(name)
Step by step, in words
  1. name holds the text "maria": 5 characters with indexes from 0 to 4.
  2. upper() does not touch "maria". It makes a new text, "MARIA".
  3. Nobody stores the new text, and it is lost.
  4. name still holds "maria", and that is what gets printed.
  5. Another new text, "MARIA", but now = stores it in name. The old "maria" is dropped.
  6. Now name holds "MARIA".
More precisely, if you are curious
  • You cannot change a character inside a text with an index either: name[0] = "M" stops the program with TypeError: 'str' object does not support item assignment. You make a new text, for example "M" + name[1:].
  • When you have many pieces, collect them in a list and join them all at once with join:
parts = ["milk", "bread", "eggs"]
print(", ".join(parts))
Output
milk, bread, eggs

Try it

Find the bug

The user types their email with uppercase letters and spaces. The program should clean it up and let them in, but it says "No such user.". Which line has the bug?

Pick the line with the bug.

The idea

Text in parts

Often a text holds several things, separated by a sign: items with a comma, words with a space. split splits it into parts and returns a list of texts:

shopping = "milk,bread,eggs,cheese"
items = shopping.split(",")
print(f"Items: {len(items)}")
for i in range(len(items)):
print(f"{i + 1}. {items[i]}")
Output
Items: 4
1. milk
2. bread
3. eggs
4. cheese

The separator is not part of the pieces. From here on you work with a regular list: length, indexes, a loop.

This is also how you read a whole line of numbers from the keyboard: you split it and turn each part into a number. That is exactly what you were missing in the last lesson, on tables:

parts = input().split(" ")
total = 0
for p in parts:
total += int(p)
print(total)
Input
42 38 51 47 60
Output
238
More precisely, if you are curious
  • Two spaces next to each other give an empty part '' between them. split() with no argument splits on any whitespace and gives no empty parts, and it also skips the spaces at the front and at the back.
  • The opposite of split is ", ".join(items): it joins the parts with a separator.
print("a b".split(" "))
print(" a b ".split())
print(", ".join(["a", "b"]))
Output
['a', '', 'b']
['a', 'b']
a, b

Try it

Is it the same?

In Python, == compares the content of texts, letter by letter. But an uppercase and a lowercase letter are different characters. The input is Sofia:

What will the program print?

city = input()
print(city == "Sofia")
print(city == "sofia")
print(city.lower() == "sofia")
Answer
More precisely, if you are curious

There is also the operator is. It does not compare the letters: it asks whether both sides are one and the same object in memory. The text read from the keyboard is a new object, so with the input admin you get this:

user = input()
print(user is "admin")
print(user == "admin")
Output
False
True

Always compare text with ==.

Exercise

Names and words

Solve the exercises in your editor. The text is read from the keyboard as a whole line.

1. The name backward. Read a name and print it from back to front. You go through the indexes from the last one down to 0 and append the characters to a new text.

Input
Maria
Output
airaM

2. Word count. Read a sentence and count the words. There can be more than one space between words, and there can be spaces at the start and at the end. Hint: a word starts where the character is not a space and the one before it is a space (or there is none before it).

Input
Today is a holiday
Output
Words: 4

3. Palindrome. A palindrome reads the same from front to back and from back to front. Spaces and uppercase letters don't count. Remove the spaces, make the letters lowercase, and compare the first character with the last, the second with the one before last, and so on.

Input
Never odd or even
Output
It is a palindrome
Input
Coffee with milk
Output
Not a palindrome

Exercise

Checks and counting

4. Strong password. Ask for a password until the user enters a strong one: at least 8 characters, at least one digit, one uppercase and one lowercase letter. After each weak password, say what is required. Hint: while True with break when the password is strong, and a check of each character with isdigit, isupper, islower.

Input
coffee
coffee2026
Coffee2026
Output
Password:
Weak password: at least 8 characters, a digit, an uppercase and a lowercase letter.
Password:
Weak password: at least 8 characters, a digit, an uppercase and a lowercase letter.
Password:
Password accepted.

More exercises

  • Commas instead of spaces. Read a sentence and replace every space with a comma. Tomorrow we leave for Varna → Tomorrow,we,leave,for,Varna.
  • The longest name. Read names separated by commas and print the longest one. Ana,Kristina,Peter → Kristina.
  • Vowels as stars. Replace every vowel (a, e, i, o, u) with *, whether it is uppercase or lowercase. I love coffee → * l*v* c*ff**.
  • Letter frequency. Count how many times each letter appears in the text, uppercase or lowercase alike. Hint: a list of 26 counters, one for each letter from 'a' to 'z'. The index of the letter c is ord(c) - ord("a"). Print only the letters that appear.
  • Character chart. Like the exercise above, but instead of the number, print that many stars: a: ****.
  • How many times each word. Read a sentence and for each different word print how many times it appears. Hint: split it into words, and for each word check whether it was already counted earlier in the list.
  • Sorting by length. Read words separated by spaces and print them from the shortest to the longest. Sort the list the way you sorted numbers, but compare the lengths.
  • Sentence count. Count the sentences in a text: each one ends with ., ! or ?. Watch out for ... and ?!: they end one sentence, not three.
  • Balanced brackets. Check whether the brackets in a text are balanced. With one kind of bracket, a counter is enough: ( adds 1, ) subtracts 1. The counter must never drop below 0, and at the end it must be 0. With three kinds, (), [], {}, you need a list of characters in which you keep the open brackets, and a counter of how full it is: at a closing bracket, the last open one must be of the same kind. {[()]} is balanced, ([)] is not.

Test

Check yourself

1. What does len("Cafe") give?
2. What does the line name.upper() do on its own, without an assignment?
3. What does "Varna" == "varna" give in Python?
4. What is the difference between 'a' and "a" in Python?
5. What does "Mon,Wed,Fri".split(",") give?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·