Command Palette

Search for a command to run...

Hectal
PHASE 3Beginner ~27 min· topic 2 of 7

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.

main.pywhole filepython
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.

main.pywhole filepython
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.

main.pywhole filepython
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.

main.pywhole filepython
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)                   # True

05Check 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.

main.pywhole filepython
name = "photo.png"

print(name.endswith(".png"))               # True
print(name.endswith((".jpg", ".png")))     # True  (either one)
print("https://hectal.in".startswith("http"))   # True

06Case 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.

main.pywhole filepython
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())   # hELLO

07removeprefix, 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.

main.pywhole filepython
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.

main.pywhole filepython
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())         # False

Try it yourself

  1. 1

    Forget to keep the result

    Write name = " asha ", then name.strip() on its own line, then print(repr(name)). The spaces are still there. Now change the line to name = name.strip() and run again.

  2. 2

    Clean a messy sentence

    Take " the QUICK brown fox ". Use split() and " ".join(...) to collapse the extra spaces, then .lower() and .title(). Print each step.

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

Trim, split, join and replace New tab

Look at the quotes in the output: `repr` makes invisible spaces and newlines visible.

Sign in to run this example in your browser.

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
bbaa
Search, case and checks New tab
Sign in to run this example in your browser.

Expected 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, removesuffix and partition Python 3.9+ New tab

`removeprefix` and `removesuffix` arrived in Python 3.9. Compare `lstrip("ab")` with `removeprefix("ab")` on the same word.

Sign in to run this example in your browser.

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

main.pywhole filepython
text = "hello"
print(text.find("z"))
print(text.index("z"))
terminal
$ python main.py
── what you'll see ──
-1
Traceback (most recent call last):
File "main.py", line 3, in <module>
print(text.index("z"))
~~~~~~~~~~^^^^^^
ValueError: substring not found

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() is True for characters such as superscript "²", which int() cannot convert. isdecimal() is stricter and matches what int() accepts, and isnumeric() is wider (fractions, Chinese numerals). When you validate user input, isdecimal() is usually the right check, and a regular expression or try: int(...) is safer still.

  • ▸

    join is 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 that join only accepts strings, so numbers need str() first: ",".join(str(n) for n in numbers).

  • ▸

    String methods such as split, find, replace and partition are 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), while split() gives ['a', 'b']: giving a separator and giving none are different algorithms. And title() capitalises after every non-letter, so "they're".title() is "They'Re"; for names and real prose use string.capwords (from the string module of Topic 3.7) or write the rule yourself. Also prefer rsplit(sep, 1) and rpartition when the interesting separator is the last one, as in a file name "archive.tar.gz".

Remember this

  1. 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() or clean = name.strip().

  2. 2

    Trimming and splitting. strip() removes whitespace (spaces, tabs, newlines) from both ends; lstrip() and rstrip() do only the left or right end. split(sep) cuts a string at every sep and 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 with sep between them.

  3. 3

    Replacing and searching. replace(old, new) replaces every old with new (add a third number to limit how many). find(x) returns the index of the first x, or -1 if it is missing; index(x) does the same but raises ValueError (an error stop) when it is missing. count(x) counts non-overlapping occurrences. To ask only "is it there?", use the in operator: "fox" in text. startswith and endswith check the two ends, and accept a tuple (a fixed group of values in round brackets) of choices such as (".jpg", ".png").

  4. 4

    Case. upper(), lower(), title() (every word starts with a capital), capitalize() (only the first letter) and swapcase() change case. For comparing text without caring about case, prefer casefold() over lower(): it is built for this and handles letters like the German ß, which casefold turns into ss.

  5. 5

    Removing a known prefix or suffix is done with removeprefix(p) and removesuffix(s) (Python 3.9). They remove the exact text once, or do nothing if it is not there. Do not use lstrip("ab") for this: its argument is a set of characters to remove, not a word, so "banana".lstrip("ab") removes b and a and gives "nana". This is one of the most common string bugs.

  6. 6

    Splitting into exactly three parts. partition(sep) splits at the first sep and always returns three pieces: before, the separator itself, after. If the separator is missing you get (text, "", ""), so you never have to count pieces. rpartition splits at the last one.

  7. 7

    Yes/no checks. Finally the is... checks: isdigit(), isalpha(), isalnum(), isspace(), isupper(), islower(). They return True only if the string is non-empty and every character passes, so "".isdigit() is False.

Explain it without notes

01

Why does text.upper() on its own line not change text?

02

What is the difference between find and index, and between strip("ab") and removeprefix("ab")?

03

How do split and join relate, and what is special about split() with no argument?

04

When would you choose partition over split?

Practice

01

Take name = " Ada Lovelace ". Make a clean lowercase version in clean, print it with repr, then print it in title case.

02

Turn the line "name,age,city" into name | age | city using split and join.

03

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 for re (Topic 3.6) only when the text has a shape the methods cannot describe.

  • ↔

    **find's -1 versus index's exception.** -1 is easy to forget to check and silently becomes a valid index. An exception is loud. For beginners, in plus index is 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, join and replace and show the result with repr.

  • Done when you can name the difference between find and index.

  • Done when you can explain the lstrip bag-of-characters trap and use removeprefix and removesuffix instead.

  • Done when you can use partition to read a key=value line safely.

  • Done when you can predict what isdigit returns for a non-empty and an empty string.