How to Perform Case-Insensitive String Replace in Python
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."
# Replace all case variations with "NY"
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)
# Safe with special characters
text = "Learn C++ and c++ programming"
result = replace_insensitive(text, "C++", "Python")
print(result)
Output:
Learn Python and Python programming
re.escape()Special regex characters will be interpreted as patterns:
.matches any character+means "one or more"$matches end of string
Always use re.escape() when replacing user-provided or variable strings.
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)."""
# Compile patterns once
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."""
# Create pattern matching any of the keys
pattern = re.compile(
"|".join(re.escape(key) for key in replacements.keys()),
re.IGNORECASE
)
def replace_match(match):
# Look up replacement using casefolded key
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"
# Replace only first 2 occurrences
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)
# Usage
print(replace_ignore_case("Hello WORLD world", "world", "Python"))
Output:
Hello Python Python
Summary
- Use
re.sub()withre.IGNORECASEfor 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.