Working with Strings
Every receipt in our Bill Splitter is text. The venue name, the table label, the
line that reads Cafe Python — Table 12 — all of it strings. And guests hand us
messy input: stray spaces, RANDOM capitals, names typed in a hurry.
So this lesson is a cleaning kit. By the end you'll take " cafe python " and a
table number and turn them into a header worth printing.
Characters have positions
A string is a sequence of characters, and each one sits at a numbered position
called an index. Counting starts at 0, not 1 — the first character is
s[0].
Negative indexes count backwards from the end, which saves you from doing
arithmetic with len(). -1 is the last character.
Slices take a range
s[start:stop] grabs several characters at once. Here's the part that trips
everybody up on their first day, so let's find out before I tell you:
print("Cafe Python"[1:4])That asymmetry looks arbitrary, but it has a payoff: the length of a slice is
always stop - start, and s[:3] + s[3:] rebuilds the original exactly. Leave a
side blank to mean "all the way to that end."
Watch the slice actually walk the string. Step through it and keep an eye on
piece as each line runs:
Try it: change
s[5:]tos[5:9]and step through again. Predict whatsecondbecomes before you press Play.
Cleaning up messy input
Real input arrives dirty. Three methods do almost all the work: .strip() drops
whitespace from both ends, .replace() swaps text, and the case methods fix
capitalisation.
For capitalisation you have four choices, and picking the right one matters:
.title() is the one our receipt wants: it capitalises the first letter of every
word and lowercases the rest, so "THE GRILL" and "the grill" both come out as
"The Grill".
It has a quirk worth meeting now rather than in production:
print("o'brien".title())Strings never change
This is the idea that causes the most confusion, so let's hit it directly. String methods do not edit the string. They can't. They build a brand-new string and hand it back.
That means a method call on its own line accomplishes precisely nothing:
name = " cafe "
name.strip()
print(f"[{name}]")Here's the same trap as running code. Fix it so it prints the cleaned name:
This should print [cafe python] with no stray spaces — but it doesn't. Run it, then fix it.
And because a string can't be edited in place, changing one character isn't allowed either:
TypeErrorRun this and read the error. Python is telling you something true about strings. Then make it print Kafe.
Reassigning the variable is fine — s = "K" + s[1:] works. It's reaching inside
the characters that Python refuses.
Splitting and joining
.split() breaks a string into a list of pieces. .join() glues a list back into
one string. They're mirror images, and you'll reach for them constantly.
The string you call .join() on is the glue that goes between the pieces —
that's the bit people get backwards. With no argument at all, .split() breaks on
any run of whitespace, which makes counting words a one-liner:
print(len("a b c".split()))f-strings put values into text
An f-string (note the f before the quote) drops values straight into text inside
{ }. After a colon you can add a format spec that controls how the value
looks:
You can call methods inside the braces, which means the whole receipt header is one tidy expression:
Step through that one to see the cleaning happen in stages:
Two details worth noticing. The — between the name and the table is an em
dash, a longer character than a hyphen. And an f-string always produces a
string: f"{price:.2f}" gives you the text "16.80" — the number price
itself is untouched.
🎯 Your turn
Write receipt_header(restaurant, table) — the tidy line at the top of every
receipt:
receipt_header("cafe python", 12)→"Cafe Python — Table 12"receipt_header("THE GRILL", 8)→"The Grill — Table 8"
Hint — clean the name with restaurant.strip().title(), then build the line
with an f-string: f"{...} — Table {table}" (that dash is an em dash, —).
Then press ▶ Run, tap the Live App try chips, and hit ✓ Check. Green = this piece of the app is built. ✅
