Replace All Occurrences of One Substring with Another Substring in Python: Complete String Replacement Guide

Replace all occurrences of one substring with another substring in python

Replace all occurrences of one substring with another substring in python

Cleaning up messy text data is one of those tasks I run into constantly — whether it’s normalizing inconsistent formatting in a CSV, sanitizing user input, or rewriting log lines. Almost every time, it comes down to replacing one substring with another, everywhere it appears. Python gives me several ways to do this, and over time I’ve learned exactly when to reach for each one. Here’s everything I use for substring replacement, from the simple built-in method to full regex-powered replacements.

Method 1: str.replace() — The Simple, Everyday Tool

The most direct way to replace all occurrences of a substring is the built-in str.replace() method.

text = "I like cats. Cats are great. I have two cats."
new_text = text.replace("cats", "dogs")
print(new_text)
# Output: I like cats. Cats are great. I have two dogs.

Notice that "Cats" (capital C) wasn’t replaced — .replace() is case-sensitive by default, matching exact substrings only.

text = "banana"
print(text.replace("a", "o"))
# Output: bonono

By default, .replace() replaces every occurrence. If I only want to replace a limited number, I can pass a third argument, count:

text = "banana"
print(text.replace("a", "o", 2))
# Output: bonona

Case-Insensitive Replacement

Since .replace() only does exact matches, replacing case-insensitively requires either regex or manual normalization. I use re.sub() with re.IGNORECASE for this:

import re

text = "I like Cats. cats are great. I have two CATS."
new_text = re.sub("cats", "dogs", text, flags=re.IGNORECASE)
print(new_text)
# Output: I like dogs. dogs are great. I have two dogs.

Method 2: re.sub() — For Pattern-Based Replacement

When the substring I want to replace isn’t fixed text but follows a pattern — like any sequence of digits, or any word starting with a capital letter — re.sub() is the right tool.

import re

text = "Order 123 and order 456 were shipped."
new_text = re.sub(r"\d+", "[NUMBER]", text)
print(new_text)
# Output: Order [NUMBER] and order [NUMBER] were shipped.

re.sub() also supports replacement using a function, which I find incredibly useful when the replacement depends on what was matched:

import re

def double_number(match):
    number = int(match.group())
    return str(number * 2)

text = "I have 3 apples and 5 oranges."
new_text = re.sub(r"\d+", double_number, text)
print(new_text)
# Output: I have 6 apples and 10 oranges.

Method 3: Replacing Multiple Different Substrings at Once

A common real-world need is replacing several different substrings in a single pass — not just one substring repeated. Chaining .replace() calls works for a small number of replacements:

text = "cats and dogs"
text = text.replace("cats", "birds").replace("dogs", "fish")
print(text)
# Output: birds and fish

But chaining gets messy and error-prone for many replacements, and it can produce incorrect results if one replacement accidentally creates text that matches a later pattern. For that, I use re.sub() with a dictionary-driven approach:

import re

replacements = {
    "cats": "birds",
    "dogs": "fish"
}

pattern = re.compile("|".join(re.escape(key) for key in replacements))
text = "cats and dogs"

result = pattern.sub(lambda match: replacements[match.group()], text)
print(result)
# Output: birds and fish

This approach does a single pass over the string, checking all patterns simultaneously, which avoids the “replacement chain” problem where an earlier replacement accidentally gets matched and replaced again by a later step.

Method 4: str.translate() for Character-Level Replacement

When I need to replace individual characters rather than substrings — say, stripping punctuation or swapping specific characters — str.translate() combined with str.maketrans() is much faster than repeated .replace() calls.

text = "hello, world!"
table = str.maketrans("lo", "LO")
print(text.translate(table))
# Output: heLLO, wOrLd!

This is a different tool for a different job — it maps individual characters, not multi-character substrings — but it’s worth knowing about since it’s significantly faster for character-level cleanup tasks like removing punctuation.

import string

text = "Hello, World! How are you?"
table = str.maketrans("", "", string.punctuation)
print(text.translate(table))
# Output: Hello World How are you

Why Strings Are Immutable — and What That Means for Replacement

Every replacement operation in Python — whether .replace(), re.sub(), or .translate() — returns a brand-new string object. Python strings can’t be modified in place; the original string remains completely untouched.

text = "hello"
new_text = text.replace("h", "H")
print(text)      # Output: hello
print(new_text)  # Output: Hello

Internally, .replace() scans the original string for matches, then builds a new string by copying the unmatched segments and inserting the replacement text at each match point. For a string of length n with k matches, this is generally an O(n) operation — Python scans the string once, and the copying work is proportional to the total length of the result.

Performance Considerations

For a handful of replacements on typical-length strings, .replace() is plenty fast — it’s implemented in C and highly optimized. But there are a few things I keep in mind for larger-scale text processing:

import re

pattern = re.compile(r"\d+")

for line in many_lines:
    cleaned = pattern.sub("[NUM]", line)

Common Mistakes I’ve Made or Seen

Real-World Applications

FAQs

Q: Does .replace() modify the original string? No — strings in Python are immutable. .replace() always returns a new string, leaving the original unchanged.

Q: How do I replace only the first occurrence of a substring? Pass 1 as the count argument: text.replace("old", "new", 1).

Q: What’s the fastest way to replace a substring in Python? For simple, literal substring replacement, .replace() is generally the fastest since it’s implemented in C without the overhead of regex pattern matching.

Q: How do I replace substrings case-insensitively without regex? There isn’t a clean built-in way without regex — re.sub() with re.IGNORECASE is the standard approach.

Summary

Replacing substrings in Python ranges from the dead-simple str.replace() for literal text, to re.sub() for pattern-based or case-insensitive replacement, to str.translate() for fast character-level substitution. Understanding that every one of these operations returns a new string — rather than modifying the original in place — clarified a lot of confusing behavior for me early on, and knowing which tool fits which situation has made my text-processing code both cleaner and noticeably faster.

References

Exit mobile version