String Methods
Split, join, replace, and transform text with Python's rich string toolkit.
- Use split() and join() to convert between strings and lists
- Apply strip(), replace(), find(), startswith(), endswith()
- Format strings with advanced f-string syntax
- Understand immutability, string methods return new strings
The immutable string
A string is finished the moment it is created. Every method that appears to edit it actually returns a new string, leaving the original untouched:
name = "alice"
upper = name.upper()
print(name) # alice (unchanged)
print(upper) # ALICEThis is worth internalizing as a law: string methods never mutate; they hand back freshly built copies. Once you expect new strings, the toolset becomes predictable, and the occasional while loop that seemingly does nothing collapses into a reassignment.
Splitting and joining
The two most transportable operations are exact inverses. Splitting breaks a string on a delimiter; joining glues a sequence back together with a delimiter:
sentence = "hello world python"
words = sentence.split() # ['hello', 'world', 'python']
back = " ".join(words) # 'hello world python'
csv_line = "apple,banana,cherry"
fruits = csv_line.split(",") # ['apple', 'banana', 'cherry']Written as equations, they undo each other:
Note the asymmetry: split() with no argument splits on runs of whitespace, multiple spaces collapse, while a lowercase space is your delimiter in " ".join(words). The join delimiter is what you want between pieces, hence ",", not "".
Searching and testing
text = "Hello, World!"
text.startswith("Hello") # True
text.endswith("!") # True
text.find("World") # 7 (index of first match, -1 if not found)
text.count("l") # 3
text.replace("World", "Python") # 'Hello, Python!'startswith and endswith are yes/no questions about the edges of the string, cheap guards that replace slicing. find answers where, returning the first index where the substring begins, or when the search fails. count tallies non-overlapping occurrences; replace swaps every match for a substitute.
Case and whitespace
"hello".upper() # 'HELLO'
"HELLO".lower() # 'hello'
" hi ".strip() # 'hi' (removes leading/trailing whitespace)
" hi ".lstrip() # 'hi ' (left only)
" hi ".rstrip() # ' hi' (right only)
"hello world".title() # 'Hello World'strip trims the padding that pollution adds, the stray spaces around pasted input. title capitalizes each word’s first letter, the suburban disguise for data entry sloppiness. Each is a transformation with one purpose, best reached for by its name rather than memorized.
Advanced f-string formatting
The f-string is a layout function: declarative columns and precision. Alignment with a width, and number formatting with a spec:
price = 19.999
name = "Widget"
# Width and alignment
print(f"|{name:<15}|") # |Widget | (left-align, width 15)
print(f"|{name:>15}|") # | Widget| (right-align)
print(f"|{name:^15}|") # | Widget | (center)
# Number formatting
print(f"{price:.2f}") # 20.00
print(f"{42:05d}") # 00042 (zero-padded)
print(f"{0.857:.1%}") # 85.7% (percentage)The % spec is a small multiplication by and a sign: . The .2f rounds to two decimals in the display while the underlying number stays whole. Alignment turns a ragged column of values into a named table, presentation without arithmetic in the body.
A worked example: cleaning the pasted line
The tools snap into a pipeline for the messiest real-world input, a line pasted from a table:
raw = " apple, banana, cherry "
cleaned = raw.strip()
fruits = cleaned.split(", ")
print(fruits) # ['apple', 'banana', 'cherry']
back = ", ".join(fruits)
print(back) # 'apple, banana, cherry'Three gestures, one circuit: strip peels the padding that pasting brings, split cuts it into pieces, join re-glues with the chosen separator. The inverse pair split/join is the bridge between text and list, the same relation as the opening equation.
Common pitfalls
- Forgetting what no-argument
split()is. It splits on runs of whitespace; asking it to split on the empty string is not a choice it offers. - Expecting
find()to raise on absent substrings. It returns . Check before slicing on it. - Trying to modify a string in place. There is no in-place edit; reassign the result.
joinsits on the delimiter,spliton the string." ".join(words), notwords.join(" "), the separator owns the method, and forgetting which is which yields anAttributeError.
🧩 Challenges
🧩 Challenge, think first, then reveal
Write title_case(s) that capitalizes the first letter of every word: title_case("hello world") → "Hello World".
💡 Answer: return s.title(), Python's built-in does exactly this; sometimes one line is the whole solution.
🧩 Challenge, think first, then reveal
Given "one,two,,three", split on commas and drop the empty strings.
💡 Answer: [x for x in s.split(",") if x] or list(filter(None, s.split(","))), the empty string is falsy, so the truthiness filter discards it without a length check.
🤔 Socratic Questions
- Why does
find()return instead of raising an error? What does each choice cost? - How do you reverse a string? Is there a method for that, or does the answer live elsewhere?
- When is
str.replace()the wrong tool, and what fits a more delicate substitution instead?
✅ Quick check
1. What does "a,b,c".split(",") return?
2. What does "hello".find("xyz") return?