Skip to content

How to Perform Case-Insensitive String Replace in Python

Learn how to replace text case-insensitively in Python using re.sub() with re.IGNORECASE, handle special characters with re.escape(), and optimize performance with compiled regex patterns.

Python's built-in .replace() method is strictly case-sensitive. To replace "Apple", "apple", and "APPLE" with the same replacement, you need to use regular expressions.

Using re.sub() with IGNORECASE

The re module provides the re.IGNORECASE flag (or its shorthand re.I) for case-insensitive matching:

import re

text = "New York, new york, NEW YORK are all the same city."

result = re.sub(r"new york", "NY", text, flags=re.IGNORECASE)

print(result)

Output:

NY, NY, NY are all the same city.

Using the Inline Flag

You can embed the flag directly in the pattern using (?i):

import re

text = "Apple, apple, APPLE - all fruits."

result = re.sub(r"(?i)apple", "orange", text)

print(result)

Output:

orange, orange, orange - all fruits.

Handling Special Characters

If your search term contains regex special characters (like ., *, +, $), use re.escape() to treat them as literal text:

import re


def replace_insensitive(text: str, old: str, new: str) -> str:
    """Replace all occurrences of 'old' with 'new' (case-insensitive)."""
    pattern = re.compile(re.escape(old), re.IGNORECASE)
    return pattern.sub(new, text)


text = "Learn C++ and c++ programming"
result = replace_insensitive(text, "C++", "Python")

print(result)

Output:

Learn Python and Python programming

Compiled Regex for Performance

When performing multiple replacements in a loop, compile the regex pattern once for better performance:

import re


def filter_comments(comments: list, bad_words: list) -> list:
    """Replace bad words with asterisks (case-insensitive)."""
    patterns = [
        re.compile(re.escape(word), re.IGNORECASE)
        for word in bad_words
    ]

    filtered = []
    for comment in comments:
        for pattern in patterns:
            comment = pattern.sub("****", comment)
        filtered.append(comment)

    return filtered


bad_words = ["spam", "scam", "fake"]
comments = [
    "This is SPAM content",
    "Total Scam alert!",
    "Great product, not fake",
    "Lovely genuine post"
]

for comment in filter_comments(comments, bad_words):
    print(comment)

Output:

This is **** content
Total **** alert!
Great product, not ****
Lovely genuine post

Replacing Multiple Patterns at Once

Combine multiple words into a single regex pattern for efficiency:

import re


def multi_replace_insensitive(text: str, replacements: dict) -> str:
    """Replace multiple words case-insensitively."""
    pattern = re.compile(
        "|".join(re.escape(key) for key in replacements.keys()),
        re.IGNORECASE
    )

    def replace_match(match):
        word = match.group(0)
        for key, value in replacements.items():
            if key.casefold() == word.casefold():
                return value
        return word

    return pattern.sub(replace_match, text)


text = "Visit New York or Los Angeles this summer."
replacements = {
    "New York": "NYC",
    "Los Angeles": "LA"
}

result = multi_replace_insensitive(text, replacements)
print(result)

Output:

Visit NYC or LA this summer.

Preserving Original Case

Sometimes you want to replace text while preserving the original's case pattern:

import re


def replace_preserve_case(text: str, old: str, new: str) -> str:
    """Replace while attempting to preserve case pattern."""

    def match_case(match):
        original = match.group(0)

        if original.isupper():
            return new.upper()
        elif original.islower():
            return new.lower()
        elif original.istitle():
            return new.title()
        else:
            return new

    pattern = re.compile(re.escape(old), re.IGNORECASE)
    return pattern.sub(match_case, text)


text = "The APPLE fell from the apple tree. Apple pie is great."
result = replace_preserve_case(text, "apple", "orange")

print(result)

Output:

The ORANGE fell from the orange tree. Orange pie is great.

Limiting Replacements

Control how many replacements occur using the count parameter:

import re

text = "cat CAT Cat cAt CaT"

result = re.sub(r"cat", "dog", text, count=2, flags=re.IGNORECASE)

print(result)

Output:

dog dog Cat cAt CaT

Method Comparison

Method Use Case Handles Special Chars
str.replace() Exact case match only Yes (literal)
re.sub() Case-insensitive Needs re.escape()
Compiled regex Multiple replacements Needs re.escape()

Complete Utility Function

A production-ready function combining all best practices:

import re
from functools import lru_cache


@lru_cache(maxsize=128)
def _get_pattern(text: str) -> re.Pattern:
    """Cache compiled patterns for repeated use."""
    return re.compile(re.escape(text), re.IGNORECASE)


def replace_ignore_case(
    text: str,
    old: str,
    new: str,
    count: int = 0
) -> str:
    """
    Replace occurrences of 'old' with 'new' (case-insensitive).

    Args:
        text: The input string
        old: The substring to find
        new: The replacement string
        count: Maximum replacements (0 = unlimited)

    Returns:
        The modified string
    """
    if not old:
        return text

    pattern = _get_pattern(old)
    return pattern.sub(new, text, count=count)


print(replace_ignore_case("Hello WORLD world", "world", "Python"))

Output:

Hello Python Python

Summary

  • Use re.sub() with re.IGNORECASE for case-insensitive replacement.
  • Use re.escape() to safely handle special regex characters.
  • Compile patterns when performing repeated replacements for better performance.
  • Consider preserving case when replacing text in user-facing content.
Navigation