Working with text — indexing, slicing, and f-strings
Pulling pieces out of text, cleaning it, changing it, and building readable messages with f-strings — plus the rule that text cannot be modified in place.
How do you want to learn?
The problem we are solving
A name arrives from a form: " Rafi Ahmed ". Extra spaces at both ends, and what you need is the first name only, plus a message — "Welcome, Rafi!".
That work — cleaning text, pulling pieces out of it, and building something new from them — is among the most frequent tasks in programming. Usernames, email addresses, ids, filenames, addresses, whatever an API sends back: all text.
And one more thing will become clear today, the kind that costs hours when you do not know it: in Python, text cannot be modified. Writing name.upper() does not make name uppercase. Why not, and what to do instead, is the most valuable part of this chapter.
By the end of this chapter you can
- Reach any character by index, from the front and from the back
- Cut a section out with a slice
- Clean and change text with
strip,upper,lower,replaceandsplit - Explain why the result of a method has to be kept
- Build readable messages with f-strings
Prerequisites: Arithmetic — division, remainders, and the decimal trap.
Quotes — one or two
To Python, 'Rafi' and "Rafi" are the same thing. Both exist so that quotes inside the text cause no trouble:
print("It's working")
print('She said "yes"')It's working
She said "yes"Three quotes hold text that spans several lines:
note = """Dear customer,
Your order is confirmed.
Thank you."""
print(note)Dear customer,
Your order is confirmed.
Thank you.And \n produces a new line, \t a tab:
print("Name:\tRafi\nRole:\tLearner")Name: Rafi
Role: LearnerLength and index
word = "PYTHON"
print(len(word))
print(word[0])
print(word[1])
print(word[-1])
print(word[-2])6
P
Y
N
OTwo things to fix in your head:
Counting starts at zero. The first character is index 0, the second 1. So in a six-character word the last index is 5, not 6. Ask for word[6] and you get an IndexError. This "one too many" mistake is so common it has its own name: an off-by-one error.
Negative indexes count from the back. word[-1] is the last character, word[-2] the one before. It is the easy way to reach the end without knowing the length.
Slices — cutting a section out
word = "PROGRAMMING"
print(word[0:7])
print(word[7:11])
print(word[:7])
print(word[7:])
print(word[-4:])PROGRAM
MING
PROGRAM
MING
MINGword[a:b] means from a up to but not including b. The end index is left out.
That feels awkward at first, and it buys you something: word[0:7] and word[7:11] join up exactly, with no character repeated and none missed. Leaving out the first number means "from the very beginning", and leaving out the second means "all the way to the end".
Text cannot be modified
This is the most important rule in this chapter:
name = "rafi"
name[0] = "R"Traceback (most recent call last):
File "D:\python-lab\lesson-06\demo.py", line 2, in <module>
name[0] = "R"
~~~~^^^
TypeError: 'str' object does not support item assignmentThe first File line shows the full path of your file, so on your computer it will look different. The real message is on the last line: a character inside existing text cannot be swapped out. So how does uppercasing or trimming work at all? The answer: Python does not change the original, it builds a new piece of text and hands it back.
name = " rafi "
print(name.strip())
print(name.strip().upper())
print("After all that, name is still:", name)rafi
RAFI
After all that, name is still: rafiname did not change at all. strip() produced a new, clean piece of text, and we merely printed it — we never stored it.
So you have to keep the result:
name = " rafi "
clean_name = name.strip().upper()
print(clean_name)RAFIOr assign it back to the same name — name = name.strip(). This one mistake, calling a method and dropping the result, happens to everybody early on. And it raises no error, which is why it takes a while to spot.
Useful methods
raw = " Rafi Ahmed "
print(raw.strip())
print(raw.strip().lower())
print(raw.strip().upper())
print(raw.strip().replace(" ", "_"))
print(len(raw), len(raw.strip()))
print("rafi" in raw.lower())Rafi Ahmed
rafi ahmed
RAFI AHMED
Rafi_Ahmed
14 10
Truestrip()— trims whitespace at the start and end (not in the middle)lower()/upper()— changes casereplace(a, b)— putsbeverywhereaappearedin— says whether one piece of text occurs inside another
And split() breaks text into pieces:
full_name = "Rafi Ahmed Khan"
parts = full_name.split(" ")
print(parts)
print(parts[0])
print(len(parts))['Rafi', 'Ahmed', 'Khan']
Rafi
3The thing in square brackets is a list, which has its own chapter later in the course. For now just know that split() returns the pieces that way, and that an index gets one piece out.
Clean before you compare. If a user types"Rafi ", that is not equal to"rafi"— a trailing space and a capital letter make two differences between them. Which is why running.strip().lower()before comparing is close to a universal habit in real projects.
f-strings — the easy way to build a message
Mixing text and numbers has been clumsy so far. An f-string makes it simple: an f before the quote, and anything you like inside curly braces {}:
name = "Rafi"
items = 3
price = 12.5
print(f"Hello, {name}!")
print(f"{items} items cost {items * price}")
print(f"Rounded: {items * price:.2f}")Hello, Rafi!
3 items cost 37.5
Rounded: 37.50Notice three benefits: you can calculate inside the braces (items * price), you never think about types (numbers become text on their own), and :.2f pins the number of decimal places — which every display of a monetary figure needs.
Have a look at what happens when the f is forgotten:
name = "Rafi"
print("Hello, {name}")Hello, {name}No error, just a wrong message. Having seen it once makes it easy to catch later.
A complete example
account.py:
# Turn a raw form entry into a clean display name and a login id
raw_input_name = " Rafi Ahmed "
domain = "example.com"
clean = raw_input_name.strip()
parts = clean.split(" ")
first_name = parts[0]
last_name = parts[-1]
login_id = f"{first_name.lower()}.{last_name.lower()}"
email = f"{login_id}@{domain}"
initials = f"{first_name[0]}{last_name[0]}"
print(f"Display name : {clean}")
print(f"Login id : {login_id}")
print(f"Email : {email}")
print(f"Initials : {initials}")
print(f"Name length : {len(clean)} characters")Display name : Rafi Ahmed
Login id : rafi.ahmed
Email : [email protected]
Initials : RA
Name length : 10 charactersWhy parts[-1]? Because someone's name may have three parts. Taking the last piece from the back works whether there are two parts or three.
When it breaks
IndexError: string index out of range The index you asked for is past the end of the text. Remember that if len(word) is 6, the valid indexes are 0 to 5. For the last character, word[-1] is the safest thing to write.
TypeError: 'str' object does not support item assignment You tried to change one character inside text. That is not possible — build new text instead, e.g. word = "R" + word[1:].
I called the method and nothing changed The result was not stored anywhere. name.strip() does not change name; you need name = name.strip().
strip() is not removing the spaces in the middle strip() only works at the two ends. To remove the inner ones use replace(" ", "").
The f-string message comes out wrong Check for the f immediately before the quote. Without it, braces are printed as ordinary characters.
NameError — the name inside the f-string is unknown Whatever you wrote inside the braces was never created, or is misspelled.
Step 4 of 6 — Predict
Check your understanding
What is the output of these four lines?
word = "PYTHON"
print(word[0])
print(word[-1])
print(word[1:4])- AP N YTH
- BY N YTHO
- CP O YTH
- DP N YTHO
The intent was to print Hello, RAFI!, but the name comes out lowercase and still padded with spaces. Why?
name = " rafi "
name.strip()
name.upper()
print(f"Hello, {name}!")- AA method can only be called once on a piece of text, not twice
- BAn f-string cannot show the result of a method
- C`strip()` and `upper()` do not change the original — they return new text, so the result has to be assigned back to `name`
- D`strip()` cannot be called before `upper()`; the order has to be reversed
What does this f-string print?
item = "pen"
qty = 3
price = 12.5
print(f"{qty} x {item} = {qty * price:.2f}")- A3 x pen = 37.50
- B3 x pen = 37.5
- C{qty} x {item} = {qty * price}
- D3 x pen = 3 * 12.5
Answering needs an account
Sign in to check your answers
The questions are above, and working them out in your head is the part that matters. Sign in to see the answers, the explanations and the three-level hints.
Your turn
Write a file called slug.py that turns a title into a form suitable for a web address.
Starting value: title = " Learn Python Step By Step "
The output should be:
Title : Learn Python Step By Step
Slug : learn-python-step-by-step
Slug length: 25Four conditions:
- Trim the extra spaces at both ends
- Lowercase everything
- Replace the inner spaces with dashes
- Print all three lines with f-strings
Then do one extra thing: change title to " Python for Beginners " and run it. If the new title comes out right without you touching the code, it means you wrote a real calculation instead of typing the answers in by hand.
There is more in this mission
What you read above is the complete mission — nothing was cut out of it. Pro adds:
- What actually happens underneath — how Python runs this
- The full solution to the exercise, worked step by step
- Harder extra exercises
- The interview question on this topic, with a model answer
Step 6 of 6
Stretch — the chapter quiz
Ten questions from easy to hard. The last ones are difficult on purpose.
Sign in to take the quiz