Python strings are immutable sequences of Unicode characters. Every string method returns a new string — it never modifies the original. This guide covers every built-in string method with examples, including slicing, formatting, and the most common real-world patterns.
Quick Reference
| Method | What it does |
|---|---|
s.upper() / s.lower() |
Convert case |
s.title() / s.capitalize() |
Capitalise words / first char |
s.strip() / s.lstrip() / s.rstrip() |
Remove whitespace (or chars) |
s.split(sep) |
Split into list |
s.rsplit(sep, maxsplit) |
Split from right |
s.splitlines() |
Split on line endings |
sep.join(iterable) |
Join list into string |
s.replace(old, new) |
Replace substrings |
s.find(sub) / s.rfind(sub) |
Index of first/last match (-1 if not found) |
s.index(sub) / s.rindex(sub) |
Like find but raises ValueError |
s.count(sub) |
Count non-overlapping occurrences |
s.startswith(prefix) |
Starts with prefix? |
s.endswith(suffix) |
Ends with suffix? |
s.in (sub in s) |
Contains substring? |
s.format(**kwargs) |
Format string |
f"..." |
f-string (preferred) |
s.zfill(width) |
Pad with zeros on left |
s.ljust(w) / s.rjust(w) / s.center(w) |
Pad with spaces |
s.encode(encoding) |
Encode to bytes |
b.decode(encoding) |
Decode bytes to string |
s.isdigit() / s.isalpha() / s.isalnum() |
Character class checks |
s.isspace() / s.isupper() / s.islower() |
More checks |
s.translate(table) |
Character-by-character replace |
s.maketrans(x, y) |
Build translation table |
Creating Strings
# Single, double, triple quotes
name = 'Ana'
greeting = "Hello, world!"
poem = """Line one
Line two
Line three"""
# Raw string — backslashes not interpreted
path = r"C:\Users\ana\docs"
regex = r"\d+\.\d+"
# Byte string
data = b"binary content"
# f-string (Python 3.6+)
age = 30
msg = f"Ana is {age} years old" # "Ana is 30 years old"
msg = f"Pi is {3.14159:.2f}" # "Pi is 3.14"
msg = f"Hex: {255:#x}" # "Hex: 0xff"
msg = f"{name!r}" # "'Ana'" (repr)
msg = f"{name!s}" # "Ana" (str)
msg = f"{name!a}" # "'Ana'" (ascii)
# Python 3.12+ — nested quotes inside f-strings
label = f"Result: {', '.join(['a', 'b', 'c'])}"
Slicing
s = "Hello, World!"
s[0] # "H"
s[-1] # "!"
s[7:] # "World!"
s[:5] # "Hello"
s[7:12] # "World"
s[::2] # "Hlo ol!" (every 2nd char)
s[::-1] # "!dlroW ,olleH" (reverse)
# Safe slice — never raises IndexError
s[100:] # "" (not an error)
Case Conversion
s = "hello, WORLD!"
s.upper() # "HELLO, WORLD!"
s.lower() # "hello, world!"
s.title() # "Hello, World!"
s.capitalize() # "Hello, world!" (only first char up, rest down)
s.swapcase() # "HELLO, world!"
# Comparison ignoring case
"Python".casefold() == "python" # True
"Straße".casefold() # "strasse" (German ß → ss)
"Python".lower() == "python" # True (works for ASCII, prefer casefold for Unicode)
Searching and Finding
s = "the cat sat on the mat"
# find returns index, -1 if not found
s.find("cat") # 4
s.find("dog") # -1
s.find("at", 5) # 8 (search from index 5)
s.rfind("at") # 19 (last occurrence)
# index raises ValueError if not found
s.index("cat") # 4
# s.index("dog") # ValueError!
# contains
"cat" in s # True
"dog" in s # False
# count
s.count("at") # 3
s.count("the") # 2
# startswith / endswith (accept tuple of prefixes)
"readme.md".endswith((".md", ".txt")) # True
"image.png".startswith(("img", "image")) # True
Replacing
s = "banana"
s.replace("a", "o") # "bonono"
s.replace("a", "o", 1) # "bonana" (max 1 replacement)
s.replace("an", "") # "bna"
# Remove a character
"hello world".replace(" ", "") # "helloworld"
# Chain replacements
text = "Hello\r\nWorld\r\n"
text.replace("\r\n", "\n") # "Hello\nWorld\n"
# translate for multiple single-char replacements (faster than chaining replace)
table = str.maketrans("aeiou", "AEIOU")
"hello world".translate(table) # "hEllO wOrld"
# Delete specific characters with translate
delete_table = str.maketrans("", "", "aeiou")
"hello world".translate(delete_table) # "hll wrld"
Splitting and Joining
# split — default splits on any whitespace, removes empty strings
" hello world ".split() # ["hello", "world"]
"a,b,,c".split(",") # ["a", "b", "", "c"]
"a,b,c".split(",", maxsplit=1) # ["a", "b,c"]
# rsplit — split from right
"path/to/file.txt".rsplit("/", 1) # ["path/to", "file.txt"]
# splitlines — handles \n, \r\n, \r
"line1\nline2\r\nline3".splitlines() # ["line1", "line2", "line3"]
# partition — returns (before, sep, after), always 3 parts
"host:port".partition(":") # ("host", ":", "port")
"no sep here".partition(":") # ("no sep here", "", "")
# join — join iterable with separator
", ".join(["a", "b", "c"]) # "a, b, c"
"".join(["h", "e", "y"]) # "hey"
"\n".join(["line1", "line2"]) # "line1\nline2"
# join is much faster than concatenation in a loop
# WRONG (slow): result = ""; for word in words: result += word + " "
# RIGHT (fast): result = " ".join(words)
Stripping Whitespace
s = " hello world "
s.strip() # "hello world" (both ends)
s.lstrip() # "hello world " (left only)
s.rstrip() # " hello world" (right only)
# Strip specific characters (any combination, not a substring)
"---TITLE---".strip("-") # "TITLE"
"xxABCxx".strip("x") # "ABC"
"/path/to/dir/".strip("/") # "path/to/dir"
# Python 3.9+ — remove prefix/suffix exactly (not char-by-char)
"Hello, World!".removeprefix("Hello, ") # "World!"
"Hello, World!".removesuffix("!") # "Hello, World"
# removeprefix/removesuffix return original if no match (no error)
"World".removeprefix("Hello, ") # "World"
Padding and Alignment
# zfill — pad with zeros (useful for codes, IDs)
"42".zfill(5) # "00042"
"-42".zfill(5) # "-0042" (sign preserved)
# ljust / rjust / center (default fill char is space)
"hi".ljust(10) # "hi "
"hi".rjust(10) # " hi"
"hi".center(10) # " hi "
"hi".center(10, "-") # "----hi----"
# f-string equivalent (preferred)
f"{'hi':<10}" # "hi " (left align)
f"{'hi':>10}" # " hi" (right align)
f"{'hi':^10}" # " hi " (center)
f"{'hi':-^10}" # "----hi----" (fill char -)
f"{42:05d}" # "00042" (zero-pad integer)
String Formatting
# f-strings (modern, Python 3.6+)
name, price = "Widget", 9.99
f"{name} costs ${price:.2f}" # "Widget costs $9.99"
f"{1_000_000:,}" # "1,000,000"
f"{0.75:.1%}" # "75.0%"
f"{255:08b}" # "11111111" (binary)
f"{255:#010x}" # "0x000000ff"
# str.format() (older style, still widely used)
"{} costs ${:.2f}".format(name, price)
"{name} costs ${price:.2f}".format(name=name, price=price)
# % formatting (legacy, avoid in new code)
"%s costs $%.2f" % (name, price)
# Template strings (safe for user-controlled strings)
from string import Template
t = Template("$name costs $$price")
t.substitute(name="Widget", price=9.99) # "Widget costs $9.99"
Checking String Content
# Character class predicates
"123".isdigit() # True
"abc".isalpha() # True
"abc123".isalnum() # True
" ".isspace() # True
"HELLO".isupper() # True
"hello".islower() # True
"Hello World".istitle() # True
# isdigit vs isnumeric vs isdecimal (subtle differences)
"²".isdigit() # True (superscript 2)
"²".isnumeric() # True
"²".isdecimal() # False (not a decimal digit 0-9)
"½".isnumeric() # True (fraction)
"½".isdigit() # False
# For ASCII digit check use:
"123".isdecimal() # True — safest for "is this a plain number?"
# Check if valid Python identifier
"my_var".isidentifier() # True
"2var".isidentifier() # False
"class".isidentifier() # True (but it's a keyword — check separately)
import keyword
keyword.iskeyword("class") # True
Encoding and Bytes
s = "Hello, 世界"
# Encode string → bytes
b = s.encode("utf-8") # b'Hello, \xe4\xb8\x96\xe7\x95\x8c'
b = s.encode("utf-16")
b = s.encode("ascii", errors="ignore") # b'Hello, '
b = s.encode("ascii", errors="replace") # b'Hello, ??'
b = s.encode("ascii", errors="xmlcharrefreplace") # b'Hello, 世界'
# Decode bytes → string
b.decode("utf-8")
b.decode("utf-8", errors="replace") # replace undecodable bytes with ?
# Check encoding
import chardet # pip install chardet
chardet.detect(b) # {"encoding": "utf-8", "confidence": 0.99}
Real-World Patterns
Parse a CSV line
line = "Ana,30,Podgorica"
name, age, city = line.split(",")
# name="Ana", age="30", city="Podgorica"
# Handle quoted fields with csv module instead
import csv
row = next(csv.reader(['Ana,"City, Town",30']))
# ["Ana", "City, Town", "30"]
Clean user input
def clean(text: str) -> str:
return text.strip().lower().replace("\r\n", "\n")
raw = " Hello World \r\n"
clean(raw) # "hello world \n"
Build a slug
import re
def slugify(text: str) -> str:
text = text.lower().strip()
text = re.sub(r"[^\w\s-]", "", text)
text = re.sub(r"[\s_-]+", "-", text)
text = text.strip("-")
return text
slugify("Hello, World! 2024") # "hello-world-2024"
Extract domain from URL
url = "https://www.example.com/path?q=1"
domain = url.split("//")[-1].split("/")[0] # "www.example.com"
# Or with urllib
from urllib.parse import urlparse
urlparse(url).netloc # "www.example.com"
Truncate text with ellipsis
def truncate(text: str, max_len: int = 100) -> str:
if len(text) <= max_len:
return text
return text[:max_len - 3].rstrip() + "..."
truncate("A very long piece of text here", 20) # "A very long piece..."
Count words
text = " Hello world how are you "
word_count = len(text.split()) # 5 (split() handles multiple spaces)
Wrap long text
import textwrap
text = "This is a very long line that needs to be wrapped at a reasonable column width."
print(textwrap.fill(text, width=40))
# This is a very long line that needs
# to be wrapped at a reasonable column
# width.
textwrap.dedent("""
Hello
World
""").strip() # "Hello\nWorld"
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
s[0] = "H" |
Strings are immutable — raises TypeError |
s = "H" + s[1:] |
"".join(x) on non-strings |
TypeError: sequence item must be str |
"".join(str(x) for x in items) |
s.split() vs s.split(" ") |
split() collapses whitespace; split(" ") keeps empty strings |
Use split() for general whitespace |
s.find() vs s.index() |
find returns -1; index raises ValueError |
Use find when absence is normal |
"ab" * 3 confusion |
"ababab" — not "aabbbb" |
Use "".join(c * 3 for c in "ab") if needed |
s.upper() == other without normalising |
Unicode case comparison fails | Use s.casefold() for robust case-insensitive compare |
+ concatenation in loop |
O(n²) — creates new string each iteration | Use "".join(parts) or io.StringIO |
FAQ
How do I check if a string contains a substring?
Use in: "world" in "hello world" → True. Use .find() when you also need the position.
What's the difference between str.split() and re.split()?str.split(sep) uses a literal separator; re.split(pattern, s) uses a regular expression. For complex delimiters (multiple chars, patterns) use re.split.
How do I reverse a string?s[::-1]. Slicing with step -1 returns a reversed copy.
How do I remove all whitespace from a string?"".join(s.split()) removes all whitespace including internal spaces. s.strip() only removes leading/trailing.
How do I convert a string to a list of characters?list("hello") → ["h", "e", "l", "l", "o"]. Or [*"hello"] with unpacking.
How do I check if a string is a number?s.isdecimal() for plain integers. For floats: try: float(s) except ValueError: .... Avoid isdigit() for this — it accepts superscripts like ².