Reshaping Strings with Methods
Introduction: From Reading Text to Reshaping It
Welcome back! Units 1 and 2 were both about reading text: indexing pulled out one character, slicing pulled out a range. Now we shift from reading to reshaping.
For that, Python gives us string methods: functions that belong to the string itself and are called with dot notation, as in text.method(). They exist because real text is messy. People paste values with stray spaces, type names with inconsistent capitalization, and format phone numbers with separators we may not want. Here is the value we will clean up:
Two leading spaces, two trailing spaces, and a surname shouting in capitals. We will fix all of it with five methods: upper, lower, title, strip, and replace.
Changing Case with Upper and Lower
Let's start with the two friendliest methods. upper() converts every letter to uppercase and lower() converts every letter to lowercase. Notice the dot before the name and the empty parentheses after it; the parentheses are required because we are calling the method rather than just naming it.
Only letters are affected. Spaces, digits, and punctuation pass through untouched, which is why our four surrounding blanks survive in both output lines — the values still sit inside their padding.
lower() is also the usual tool for simple case-insensitive comparison, since "Ada" == "ada" is False while "Ada".lower() == "ada".lower() is True. (For text in other languages there is a stricter sibling, casefold(), which handles cases that lower() misses — worth knowing the name, though plain lower() is fine for the English examples in this course.)
Strings Are Immutable: Methods Return New Strings
Here is the idea that makes every method in this lesson behave predictably: Python strings are immutable. A string can never be modified in place. Instead, each method builds and returns a brand-new string, and the original stays exactly as it was. Print messy_name right after calling .upper() and we still see " Ada LOVELACE ".
That leaves two habits, and only one of them is useful:
messy_name.upper()on its own: the new string is created and immediately thrown away.shouty = messy_name.upper(): the new string is captured in a variable we can use later.
This is exactly why the code ahead writes cleaned = messy_name.strip() rather than calling strip() and hoping messy_name changes. Immutability also explains why an assignment such as messy_name[0] = "a" is impossible in Python: individual characters can be read, never overwritten.
Trimming Whitespace with Strip
Now let's deal with those padding spaces. strip() removes whitespace — spaces, tabs, and newlines — from both ends of a string. It never touches whitespace in the middle, so the single space between the two names stays.
We store the result in cleaned so we can reuse it, and print it with repr(), a handy debugging helper that shows the string surrounded by quotation marks. Since spaces are invisible, quotation marks are how we prove the trimming worked. Python also offers one-sided variants: lstrip() trims only the left end, rstrip() only the right.
Normalizing Capitalization with Title
Our value is trimmed, but "Ada LOVELACE" still looks like an argument. The title() method fixes that: it uppercases the first letter of each word and lowercases everything else in that word.
We call it on cleaned, not on messy_name, so we build on the work already done. The lowercasing half is what quietly tames LOVELACE into Lovelace. One honest caveat: title() is naive about apostrophes and internal capitals, so "o'brien" becomes "O'Brien" with an odd extra capital and "McDonald" becomes "Mcdonald". It suits display formatting more than careful name handling. For a single capital at the start of the whole string, capitalize() is the alternative.
Swapping Substrings with Replace
Case is only one kind of mess. Sometimes we need to remove characters entirely, which is where replace() comes in. Let's switch to a second value: a phone number written with separators.
replace() takes two arguments, old and new, and swaps every occurrence, not just the first — both dashes disappear in one call. Passing the empty string "" as new is the standard trick for deleting a substring, since each match is replaced with nothing at all. And if old never appears there is no error; we simply get back an unchanged copy.
Method Chaining: Combining Transformations in One Expression
Because every method returns a string, and strings have methods, we can call the next method directly on the previous result. This is called chaining, and it expresses a whole cleanup pipeline in one line.
Python evaluates left to right: messy_name is " Ada LOVELACE ", then .strip() produces "Ada LOVELACE", then .title() turns that into "Ada Lovelace". Order can matter in a chain: here .title().strip() happens to give the same answer, but a .replace() searching for "ada" would find nothing after a .title() call. Rule of thumb: chain two or three steps for readability, and split longer pipelines across named variables.
The Complete Program
All the pieces, gathered into one file:
The detail worth noticing is what is not in the output: messy_name still holds " Ada LOVELACE " when the program ends.
Method Cheat Sheet
| Method | What it does | Example on " Ada LOVELACE " |
|---|---|---|
.upper() | All letters uppercase | " ADA LOVELACE " |
.lower() | All letters lowercase | " ada lovelace " |
.title() | First letter of each word uppercase | " Ada Lovelace " |
.strip() | Removes whitespace from both ends | "Ada LOVELACE" |
.replace(old, new) | Swaps every occurrence | .replace(" ", "") gives "AdaLOVELACE" |
Every row produces a new string; not a single one edits the original.
Conclusion and Next Steps
The one idea to carry forward is immutability: a method never edits its string, so its result must be stored or used right away. Everything else in this lesson is a variation on that theme, and repr() is our small ally for making invisible spaces visible.
In Unit 4 we move from reshaping text to searching it, then break text apart and stitch it back together. Let's go clean up some text!
