Topic 3.2
The String Methods You Use Daily
In one line
A method is a built-in action attached to a value, called with a dot: text.strip(). Strings have dozens, and about twenty cover almost everything: trimming, splitting and joining, replacing, searching, changing case, removing prefixes, and checking what a string contains.
Think of it like this
A Swiss army knife. One handle, many tools, each with a name: scissors, blade, screwdriver. A string is like the handle. Write a dot after it and the name of a tool, and Python does that job on the text: "hello".upper() uses the "make capitals" tool. These tools are called methods, and they only work on the kind of value they belong to. Anything you put inside the round brackets is an argument: extra information for the tool, such as which letter to remove.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Method
- An action that belongs to a value, called with a dot, such as
text.upper(). - Whitespace
- Characters you cannot see: space, tab and newline.
- List
- An ordered row of items in square brackets, like
['a', 'b']. Phase 4 covers lists in full. - Separator (sep)
- The text you cut at when splitting, or put between pieces when joining.
- Prefix and suffix
- The start and the end of a string, such as
https://or.pdf. - Tuple
- A fixed row of items in round brackets, like
(".jpg", ".png"). Phase 4 covers tuples. - Return value
- What a method hands back. String methods return a new string; they do not change the old one.
- Casefold
- A stronger form of lowercasing, meant for comparing text regardless of case.
Step by step
01Methods return new strings
A method call is the value, a dot, the method name and round brackets. Anything inside the brackets is an argument: extra information for the method.
The first rule to learn is that the original string never changes. The result must be captured in a variable, or used straight away.
repr(name) shows the string with its quotes, so hidden spaces become visible.
name = " asha "
name.strip() # the result is thrown away!
print(repr(name)) # ' asha ' (unchanged)
name = name.strip() # keep the new string
print(repr(name)) # 'asha'02Trim whitespace with strip
Text from a file, a form or a user nearly always has stray spaces or a newline at the end. strip() is the first thing to apply to such text. Giving strip an argument makes it remove those characters instead of whitespace, again as a set: "xxhixx".strip("x") is "hi".
repr() shows a string with its quotes and its invisible characters (\n is a newline), which is the right tool for checking what is really in a string.
raw = " Hello, World! \n"
print(repr(raw.strip())) # 'Hello, World!'
print(repr(raw.lstrip())) # 'Hello, World! \n'
print(repr(raw.rstrip())) # ' Hello, World!'03Split and join are opposites
split(",") cuts at each comma and returns a list of strings. join goes the other way: you call it on the separator and give it the list. Beginners often write it backwards; remember that ", ".join(items) reads as "use comma-space to join the items".
split() with no argument is special: it splits on any amount of whitespace and drops empty pieces, which is what you want for "words in a sentence". split(sep, 2) stops after two cuts. splitlines() cuts at line breaks.
line = "apple,banana,cherry"
parts = line.split(",")
print(parts) # ['apple', 'banana', 'cherry']
print(" + ".join(parts)) # apple + banana + cherry
print("a b c".split()) # ['a', 'b', 'c']04Replace and search
replace changes every match. find tells you where something is, with -1 as the "not found" answer. Because -1 is also a valid index (the last character), always compare the result with -1 before using it as a position.
index is the strict twin of find: it raises ValueError: substring not found. Use find when absence is normal and index when absence is a bug.
text = "the quick brown fox"
print(text.replace("quick", "slow")) # the slow brown fox
print(text.find("quick")) # 4
print(text.find("slow")) # -1
print("fox" in text) # True05Check the start and the end
startswith and endswith return True or False. Pass a tuple to test several choices at once. They are the clean way to ask "is this a PDF?" or "is this a URL?", better than slicing the last four characters by hand.
name = "photo.png"
print(name.endswith(".png")) # True
print(name.endswith((".jpg", ".png"))) # True (either one)
print("https://hectal.in".startswith("http")) # True06Case methods
Use lower() to normalise text before comparing, and title() or capitalize() for display. Use casefold() when the comparison must be correct for all languages.
Many sites compare emails and usernames with lower(). For real text in many languages, casefold() is the correct tool.
text = "the quick brown fox"
print(text.upper()) # THE QUICK BROWN FOX
print(text.title()) # The Quick Brown Fox
print(text.capitalize()) # The quick brown fox
print("Hello".swapcase()) # hELLO07removeprefix, removesuffix and the lstrip trap
To remove a known beginning or ending, use removeprefix and removesuffix. They remove the exact text once, and do nothing when it is not there. strip family methods take a bag of characters, which is a different job.
url = "https://hectal.in/python"
print(url.removeprefix("https://")) # hectal.in/python
print("banana".lstrip("ab")) # nana (strips any a or b)
print("banana".removeprefix("ab")) # banana (no "ab" at the start)08partition and the is... checks
partition is the safest way to split "key = value" text: you always get three pieces, even when the separator is missing, so there is no "wrong number of pieces" crash.
The is... methods answer yes/no questions about the whole string. They need every character to qualify, and an empty string never qualifies.
key, sep, value = "timeout = 30".partition("=")
print(repr(key.strip()), repr(value.strip())) # 'timeout' '30'
print("12345".isdigit()) # True
print("12a45".isdigit()) # False
print("".isdigit()) # FalseTry it yourself
- 1
Forget to keep the result
Write
name = " asha ", thenname.strip()on its own line, thenprint(repr(name)). The spaces are still there. Now change the line toname = name.strip()and run again. - 2
Clean a messy sentence
Take
" the QUICK brown fox ". Usesplit()and" ".join(...)to collapse the extra spaces, then.lower()and.title(). Print each step. - 3
Race the traps
Predict
"banana".strip("ab"),"banana".rstrip("na")and"banana".removesuffix("na"). Run them. Which two behave as "bags of characters"?
Code & diagrams
Look at the quotes in the output: `repr` makes invisible spaces and newlines visible.
Expected output
' Hello, World! \n'
'Hello, World!'
'Hello, World! \n'
' Hello, World!'
'hi'
['apple', 'banana', 'cherry']
how many: 3
['a', 'b', 'c']
['a', 'b', 'c,d']
apple + banana + cherry
Python
a+b+c
bbaaExpected output
find quick: 4
find slow: -1
count o: 2
starts with 'the': True
ends with '.py': True
one of two endings: True
THE QUICK BROWN FOX
The Quick Brown Fox
The quick brown fox
hELLO
casefold match: True
True True True True True
empty string isdigit: False`removeprefix` and `removesuffix` arrived in Python 3.9. Compare `lstrip("ab")` with `removeprefix("ab")` on the same word.
Expected output
hectal.in/python
report
report.pdf
nana
banana
'timeout ' '=' ' 30'
'timeout' '30'
('no equals here', '', '')
('a/b', '/', 'c.txt')Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Use index on text that is not there
Run text = "hello", then print(text.find("z")) and print(text.index("z")).
text = "hello"
print(text.find("z"))
print(text.index("z"))Myth vs fact
Myth
name.strip() cleans the variable name.
Fact
It returns a new, cleaned string and leaves name as it was. You must assign the result.
Myth
lstrip("abc") removes the word abc from the start.
Fact
It removes any of the characters a, b, c from the start, as many times as they appear. Use removeprefix("abc") to remove the exact word.
Myth
find raises an error when the text is missing.
Fact
It returns -1. index is the one that raises ValueError.
Myth
"".isdigit() is True because there is no non-digit in it.
Fact
The is... methods require at least one character, so an empty string returns False.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
str.isdigit()isTruefor characters such as superscript"²", whichint()cannot convert.isdecimal()is stricter and matches whatint()accepts, andisnumeric()is wider (fractions, Chinese numerals). When you validate user input,isdecimal()is usually the right check, and a regular expression ortry: int(...)is safer still. - ▸
joinis the fast way to build a string from many pieces: it measures all the pieces once, allocates the result once and copies. Using+in a loop can be quadratic in the worst case (Topic 3.5). Note thatjoinonly accepts strings, so numbers needstr()first:",".join(str(n) for n in numbers). - ▸
String methods such as
split,find,replaceandpartitionare written in C inside CPython, so they are far faster than the same job done in a Python-level loop over characters. When a plain method can do the job, it will usually beat a regular expression for both speed and clarity. - ▸
Two traps that interviewers like.
"a b".split(" ")gives['a', '', 'b'](an empty piece for every extra space), whilesplit()gives['a', 'b']: giving a separator and giving none are different algorithms. Andtitle()capitalises after every non-letter, so"they're".title()is"They'Re"; for names and real prose usestring.capwords(from thestringmodule of Topic 3.7) or write the rule yourself. Also preferrsplit(sep, 1)andrpartitionwhen the interesting separator is the last one, as in a file name"archive.tar.gz".
Remember this
- 1
The most important fact: string methods never change the string. Strings are unchangeable (Topic 3.5), so every method returns a new string and leaves the original alone. Writing
name.strip()on its own line does nothing useful, because the result is thrown away. You must keep the result:name = name.strip()orclean = name.strip(). - 2
Trimming and splitting.
strip()removes whitespace (spaces, tabs, newlines) from both ends;lstrip()andrstrip()do only the left or right end.split(sep)cuts a string at everysepand returns a list: an ordered row of items written in square brackets, like['apple', 'banana'](Phase 4 teaches lists properly).split()with no argument splits on any run of whitespace and ignores empty pieces at the ends."sep".join(items)does the opposite: it glues the pieces back together withsepbetween them. - 3
Replacing and searching.
replace(old, new)replaces everyoldwithnew(add a third number to limit how many).find(x)returns the index of the firstx, or-1if it is missing;index(x)does the same but raisesValueError(an error stop) when it is missing.count(x)counts non-overlapping occurrences. To ask only "is it there?", use theinoperator:"fox" in text.startswithandendswithcheck the two ends, and accept a tuple (a fixed group of values in round brackets) of choices such as(".jpg", ".png"). - 4
Case.
upper(),lower(),title()(every word starts with a capital),capitalize()(only the first letter) andswapcase()change case. For comparing text without caring about case, prefercasefold()overlower(): it is built for this and handles letters like the Germanß, whichcasefoldturns intoss. - 5
Removing a known prefix or suffix is done with
removeprefix(p)andremovesuffix(s)(Python 3.9). They remove the exact text once, or do nothing if it is not there. Do not uselstrip("ab")for this: its argument is a set of characters to remove, not a word, so"banana".lstrip("ab")removesbandaand gives"nana". This is one of the most common string bugs. - 6
Splitting into exactly three parts.
partition(sep)splits at the firstsepand always returns three pieces: before, the separator itself, after. If the separator is missing you get(text, "", ""), so you never have to count pieces.rpartitionsplits at the last one. - 7
Yes/no checks. Finally the
is...checks:isdigit(),isalpha(),isalnum(),isspace(),isupper(),islower(). They returnTrueonly if the string is non-empty and every character passes, so"".isdigit()isFalse.
Explain it without notes
Why does text.upper() on its own line not change text?
What is the difference between find and index, and between strip("ab") and removeprefix("ab")?
How do split and join relate, and what is special about split() with no argument?
When would you choose partition over split?
Practice
Take name = " Ada Lovelace ". Make a clean lowercase version in clean, print it with repr, then print it in title case.
Turn the line "name,age,city" into name | age | city using split and join.
Given f = "photo.JPG", check that it is a JPEG regardless of case, and print its name without the extension.
Trade-offs
- ↔
Methods versus regular expressions. A plain method (
startswith,split,replace) is faster and easier to read than a pattern. Reach forre(Topic 3.6) only when the text has a shape the methods cannot describe. - ↔
**
find's-1versusindex's exception.**-1is easy to forget to check and silently becomes a valid index. An exception is loud. For beginners,inplusindexis often the safest pair.
Done when you can
Done when you can explain why a string method never changes the string it is called on.
Done when you can clean text with
strip,split,joinandreplaceand show the result withrepr.Done when you can name the difference between
findandindex.Done when you can explain the
lstripbag-of-characters trap and useremoveprefixandremovesuffixinstead.Done when you can use
partitionto read akey=valueline safely.Done when you can predict what
isdigitreturns for a non-empty and an empty string.