re.escape
Any text you did not write yourself — search terms, file names, prices — must go through re.escape before it becomes part of a pattern. Otherwise a dot matches anything and a stray ( is a syntax error.
Common call
re.escape('1+1=2?')
Returns
'1\\+1=2\\?' — backslashes before + and ?
Replaces
hand-escaping characters one by one
Watch out
Escape the text parts only — never the regex parts you add around them
re.escape(patternpattern — Text to be matched literally.type: str | bytes · required)
→ str | bytes
Demo
Live evaluation
What re.escape adds. Letters, digits and _ are never escaped.
Try:
Inputs
textstrany text
Code
import re re.escape('1+1=2? (yes)')
Result
'1\\+1=2\\?\\ \\(yes\\)'
Unescaped, a.c is a pattern: the dot matches b and - as well. 1+1 means one or more 1s followed by a 1, so it finds 11 and 111 but not the text 1+1. A lone ( is not even a valid pattern — the whole expression fails with re.PatternError before the escaped version runs.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| pattern | str | bytes | yes | Text to be matched literally. |
Return value
str | bytes — The text with a backslash before every character that is special in a regular expression.
Common patterns
Search for user input
Escape the term, then add your own regex around it.
import re hits = re.findall(r'\b' + re.escape(term) + r'\b', text, re.IGNORECASE)
Match any of several literal words
Escape each word, join with |. Put longer words first so they win.
import re words = sorted(keywords, key=len, reverse=True) pat = re.compile('|'.join(map(re.escape, words)))
Escaping for the replacement side
re.escape is for patterns. For repl, pass a function instead.
import re result = re.sub(re.escape(old), lambda m: new, text)
Examples
1. Special characters escaped
import re
re.escape('1+1=2? (yes)')
Returns
'1\\+1=2\\?\\ \\(yes\\)'2. Letters, digits, _ unchanged
import re
re.escape('a_b-c d')
Returns
'a_b\\-c\\ d'3. Slash and = are left alone
import re
re.escape('path/to/file.txt')
Returns
'path/to/file\\.txt'4. Literal search
import re
re.findall(re.escape('a.c'), 'abc a.c')
Returns
['a.c']5. Unescaped dot matches anything
import re
re.findall('a.c', 'abc a.c')
Returns
['abc', 'a.c']6. Bytes work too
import re
re.escape(b'a.b')
Returns
b'a\\.b'Pitfalls
1. User text straight into a pattern
An unbalanced parenthesis in the search term is a pattern error.
raw input
import re term = 'f(x' re.search(term, 'call f(x) now')
re.PatternError: missing ), unterminated subpattern at position 1
re.escape
import re term = 'f(x' re.search(re.escape(term), 'call f(x) now')
<re.Match object; span=(5, 8), match='f(x'>
2. Escaping the whole pattern
Only the literal part should be escaped — escaping \d too turns it into a literal backslash + d.
escape(all)
import re print(re.search(re.escape(r'v\d'), 'v1'))
None
escape(part)
import re re.search(re.escape('v') + r'\d', 'v1')
<re.Match object; span=(0, 2), match='v1'>
When to use
Use it
- Putting user-supplied or data-derived text inside a pattern
- Building an alternation from a list of literal words
Reach for something else
- Only literal search, no other regex parts → str.find / in / str.replace
- Escaping a replacement string → pass a function as repl instead
Notes
CPython impl
str.translate with a map of the characters ()[]{}?*+-|^$\.&~# and whitespace (space, \t, \n, \r, \v, \f) — Lib/re/__init__.py
Since 3.7
Only characters that can be special in a regex are escaped; before 3.7 characters such as ! , / : ; = @ were escaped too
Since 3.3
The _ character is no longer escaped
FAQ
Escape it with a backslash in a raw string, r'\.', or let re.escape do it for text you did not write: re.escape('3.14') gives '3\\.14'.