Back to Blog
Python

Python String Replace: Syntax and Usage

Learn how to use Python's `replace()` method, including the `count` parameter, case sensitivity, and when to use `re.sub` instead.

PythonString MethodsText Processingreplacere.sub
Illustration of a Python string being transformed by a replace operation, showing old and new substrings.

Python's str.replace(old, new[, count]) method returns a copy of a string with occurrences of old replaced by new. If count is omitted, all occurrences are replaced; if it is provided, only the first count occurrences are replaced. Because Python strings are immutable, the original string is not changed, and a new string object is returned.

Basic Usage and Return Value

The simplest call replaces all occurrences of a substring:

text = "one fish, two fish, red fish, blue fish" result = text.replace("fish", "bird") print(result) # one bird, two bird, red bird, blue bird

replace works with substrings of any length, not just single characters. It also accepts an empty string as the old argument, which inserts new at every position, including the start and end:

"abc".replace("", "-") # -a-b-c-

This behavior is rarely useful, but it can surprise developers who assume an empty pattern is ignored.

Limiting Replacements with the Count Parameter

The optional count parameter restricts how many replacements are performed from the left. This is useful when you want to replace only the first or first few occurrences:

s = "apple, apple, apple" s.replace("apple", "orange", 2) # orange, orange, apple

If count is omitted, negative, or larger than the actual number of occurrences, all occurrences are replaced. replace never matches overlapping substrings; it scans left to right and resumes after each match. For example, replacing "aa" with "b" in "aaa" yields "ba", not "bb", because the second match would need to overlap the first.

Case Sensitivity and Case-Insensitive Replacement

The replace method is case-sensitive. To make matching case-insensitive, you can normalize the string to one case before replacing, but that changes the output case. For pattern-based replacement that leaves non-matching text unchanged, re.sub with the re.IGNORECASE flag is more appropriate:

import re s = "Hello World, hello universe" re.sub("hello", "hi", s, flags=re.IGNORECASE) # hi World, hi universe

re.sub replaces all matches by default and also supports a count argument. For simple literal replacements, str.replace is faster and simpler; for case-insensitive or pattern matching, re.sub is the right tool.

Chaining Multiple Replacements

To replace several different substrings, you can chain replace calls. Each call returns a new string, so the order matters:

s = "cat and dog" s.replace("cat", "bird").replace("dog", "fish") # bird and fish

Be careful when replacement strings contain the original search string. For example, replacing "a" with "aa" in "a" gives "aa", but if you chain replacements, the second call may operate on already-replaced text. In such cases, consider a single traversal using re.sub with a callback or a dictionary mapping.

Performance and Memory Behavior

Each replace call creates a new string and copies the content, even if only one occurrence changes. This is inherent to Python's immutable string design. For a one-off replacement, the overhead is negligible. However, in a loop that repeatedly modifies a string, this can lead to quadratic time complexity because each iteration copies the growing string. Instead, collect parts in a list and join them, or use re.sub for complex transformations.

replace with a simple literal is implemented in C and is very fast. If you need to replace many different substrings, a single re.sub with a function that looks up replacements from a dictionary is often more efficient than chaining many replace calls, especially for long strings.

When to Use re.sub Instead of replace

str.replace is limited to literal substring replacement. If you need to match patterns, use re.sub. Common cases include:

  • Replacing with case-insensitive matching
  • Replacing based on regex patterns (e.g., digits, word boundaries)
  • Using a function to compute the replacement dynamically
Featurestr.replacere.sub
Pattern matchingLiteral onlyRegex patterns
Case-insensitiveNot directlyWith re.IGNORECASE
Count limitYesYes
Replacement functionNoYes
Performance for simple literalsFasterSlower

For simple literal replacements, replace is the right choice. For anything that requires pattern logic, re.sub is more expressive and avoids multiple passes over the string.

Common Pitfalls and Edge Cases

One frequent mistake is assuming replace modifies the string in place. Because strings are immutable, forgetting to assign the result leads to no change:

s = "hello" s.replace("l", "L") # result discarded print(s) # still "hello"

Another edge case is overlapping substrings. replace does not handle overlaps; it scans left to right and skips the matched portion. For example, replacing "aba" in "ababa" yields "Xba" because the first match consumes positions 0 through 2, leaving "ba". This is usually the desired behavior, but it can surprise developers expecting all possible matches.

Finally, replacing old with an empty string effectively deletes the old substring. This is a common way to remove characters or substrings:

"remove spaces here".replace(" ", "") # removespaceshere

Be aware that replace with an empty old argument inserts the replacement everywhere, which is rarely what you need. Always test edge cases with short examples to confirm the behavior matches your expectation.

Python String Replace: Syntax, Usage, and Code Examples | RYUSLOG DEV