Why this matters
Raw text rarely arrives in the shape you need. User input has stray spaces and random capitalization, CSV lines must be broken into fields, paths must be checked for extensions, and output must be assembled from pieces. Python strings come with a toolbox of methods that do these jobs in one call each, implemented in C and therefore fast. Knowing a dozen of them well covers most everyday text handling.
What a method is
A method is a function that belongs to an object's type and is called on an object with a dot:
name = "ada lovelace"
print(name.upper())
print(name.title())
print(name.count("a"))
ADA LOVELACE
Ada Lovelace
3
name.upper() means: look up the upper method on the type of name (which is str), and call it with name as the object to work on. Every string has the same methods because they all share the type str. You can list them with dir(str) and read about one with help(str.upper).
Note: Strings are immutable, so no string method changes the string. Methods that "modify" text return a new string. If you want to keep the result, assign it:
name = name.strip().
Because each method returns a string, you can chain calls; they run left to right:
raw = " Hello World "
print(raw.strip().lower().replace(" ", "_"))
hello_world
Changing case
| Method | Result for "hello World" |
|---|---|
upper() | "HELLO WORLD" |
lower() | "hello world" |
title() | "Hello World" |
capitalize() | "Hello world" |
swapcase() | "HELLO wORLD" |
To compare text without caring about case, normalize both sides: answer.lower() == "yes". (For fully correct case-insensitive comparison of international text, casefold() is stronger than lower(): "Straße".casefold() becomes "strasse".)
Removing whitespace: strip
strip() returns a copy without leading and trailing whitespace (spaces, tabs, newlines). lstrip() and rstrip() do only the left or right side:
s = "\t padded \n"
print(repr(s.strip()))
print(repr(s.lstrip()))
print(repr(s.rstrip()))
'padded'
'padded \n'
'\t padded'
repr() shows the string with quotes and escapes, so you can see invisible characters. Use it whenever whitespace is a suspect.
With an argument, strip removes any of the given characters (not a substring) from the ends: "xxhixx".strip("x") is "hi", and "...hello!!".strip(".!") is "hello".
Searching
path = "/home/ada/notes.txt"
print(path.startswith("/home"))
print(path.endswith(".txt"))
print(path.find("ada"))
print(path.find("bob"))
print(path.rfind("/"))
print(path.count("/"))
True
True
6
-1
9
3
startswith(x)andendswith(x)return booleans. They also accept a tuple of options:name.endswith((".jpg", ".png")).find(x)returns the index of the first occurrence, or-1if absent.rfind(x)searches from the right, giving the last occurrence.index(x)is likefindbut raisesValueError: substring not foundwhen absent. Useindexwhen absence would be a bug,findwhen absence is a normal case you will check.count(x)counts non-overlapping occurrences.
Combine rfind with slicing to split at the last separator, the classic file-extension recipe:
filename = "archive.tar.gz"
dot = filename.rfind(".")
print(filename[:dot])
print(filename[dot + 1:])
archive.tar
gz
Replacing
replace(old, new) returns a copy with every occurrence of old replaced; an optional third argument limits how many:
s = "a-b-c-d"
print(s.replace("-", " "))
print(s.replace("-", "", 2))
a b c d
abc-d
Splitting into pieces: split
split breaks a string into a list of strings. A list is an ordered collection written in square brackets; you will study lists properly in the collections module. For now you need two facts: you can index it just like a string (parts[0] is the first piece), and len(parts) tells you how many pieces there are.
line = "ada,36,London"
parts = line.split(",")
print(parts)
print(parts[0])
print(parts[2])
print(len(parts))
['ada', '36', 'London']
ada
London
3
Called with no argument, split() is special: it splits on any run of whitespace and ignores whitespace at the ends. That makes it ideal for words typed by humans:
print(" the quick brown\tfox ".split())
print("a,,b".split(","))
['the', 'quick', 'brown', 'fox']
['a', '', 'b']
With an explicit separator, every occurrence counts, so adjacent separators produce empty strings (as in "a,,b"). split(sep, 1) stops after the first split, handy for key=value lines whose values may contain =. splitlines() splits text into lines.
Joining pieces: join
join is the reverse of split. It is called on the separator and takes a collection of strings:
words = ["2026", "11", "01"]
print("-".join(words))
print("".join(["a", "b", "c"]))
print(", ".join("xyz"))
2026-11-01
abc
x, y, z
The last example works because a string is itself a sequence of one-character strings. The items must all be strings: "-".join([1, 2]) raises TypeError: sequence item 0: expected str instance, int found.
Why sep.join(items) instead of adding strings with + in a loop? Every + creates a new string and copies both parts, because strings are immutable. Joining n pieces with repeated + can copy the text over and over; join first measures the total length, allocates the result once, and copies each piece once.
Checking what a string contains
A family of is... methods test every character:
print("2026".isdigit())
print("abc".isalpha())
print("abc123".isalnum())
print(" ".isspace())
print("Hello".isupper())
True
True
True
True
False
"12".isdigit() is a good guard before int(...), though it says False for "-12", so it is not a complete number check. All of these return False for the empty string.
Common mistakes
- Forgetting to keep the result.
line.strip()alone does nothing useful. Writeline = line.strip(). - Calling join on the list.
["a", "b"].join(",")givesAttributeError: 'list' object has no attribute 'join'. The separator comes first:",".join(["a", "b"]). - Not checking
find.s[s.find("x"):]when"x"is absent slices from-1, giving the last character instead of an error. Check for-1. - Splitting on
" "when you meantsplit(). Double spaces produce empty strings in the list. - Forgetting the parentheses.
name.upperwithout()is the method object itself; printing it shows<built-in method upper of str object at 0x...>.
Recap
- Methods are called with a dot; string methods return new strings and never modify the original.
- Case:
upper,lower,title,capitalize,casefold. Whitespace:strip,lstrip,rstrip. - Search:
in,startswith,endswith,find/rfind(return-1),index(raises),count. replace(old, new)substitutes;splitturns a string into a list;sep.join(pieces)builds one string efficiently.is...methods test the kind of characters a string contains.
Going further: run help(str) in the REPL and skim the method list. Try partition: "key=value=x".partition("=") returns three parts, and is often the neatest way to split at the first separator.