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:

Python
messy_name = "  Ada LOVELACE  "

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.

Python
messy_name = "  Ada LOVELACE  "

# Each method returns a NEW string; the original is unchanged
print("Upper:", messy_name.upper())
print("Lower:", messy_name.lower())

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.)

text
Upper:   ADA LOVELACE  
Lower:   ada lovelace  

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.

Python
# strip() removes whitespace from both ends
cleaned = messy_name.strip()
print("Stripped:", repr(cleaned))

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.

text
Stripped: 'Ada LOVELACE'

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.

Python
# title() capitalizes the first letter of each word
print("Title:", cleaned.title())

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.

text
Title: Ada Lovelace

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.

Python
# replace() swaps every occurrence of a substring
phone = "555-123-4567"
print("Digits only:", phone.replace("-", ""))

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.

text
Digits only: 5551234567

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
# Methods chain because each one returns a string
print("Normalized:", messy_name.strip().title())

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.

text
Normalized: Ada Lovelace

The Complete Program

All the pieces, gathered into one file:

Python
messy_name = "  Ada LOVELACE  "

# Each method returns a NEW string; the original is unchanged
print("Upper:", messy_name.upper())
print("Lower:", messy_name.lower())

# strip() removes whitespace from both ends
cleaned = messy_name.strip()
print("Stripped:", repr(cleaned))

# title() capitalizes the first letter of each word
print("Title:", cleaned.title())

# replace() swaps every occurrence of a substring
phone = "555-123-4567"
print("Digits only:", phone.replace("-", ""))

# Methods chain because each one returns a string
print("Normalized:", messy_name.strip().title())

The detail worth noticing is what is not in the output: messy_name still holds " Ada LOVELACE " when the program ends.

Method Cheat Sheet

MethodWhat it doesExample 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!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal