Python Regex Cheat Sheet
1 · The lesson
readA regular expression (regex) is a pattern that describes text, such as "four digits" or "a word followed by @". Python's re module uses a pattern to find, split or replace text. For the full tutorial, see Regex.
Always write patterns as raw strings, with an r before the quote: r"\d+". In a raw string Python leaves the backslashes alone, so they reach re as you wrote them. The examples use this string:
import re s = "Order 66 shipped 2026-03-14 to ada@dev.io"
1. The functions
print(re.findall(r"\d+", s)) # ['66', '2026', '03', '14'] print(re.search(r"\d+", s).group()) # 66 print(re.match(r"\d+", s)) # None print(bool(re.fullmatch(r"\d{4}", "2026"))) # True print(re.sub(r"\d", "#", "a1b22")) # a#b## print(re.split(r"[,;]\s*", "a, b;c")) # ['a', 'b', 'c'] print([m.span() for m in re.finditer(r"\d+", "a1 b22")]) # [(1, 2), (4, 6)]
setup added so this can run · re-runs 1 earlier block on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) s = _AutoMock('s') re = _AutoMock('re') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
| Function | What it does | Returns |
|---|---|---|
re.findall(pat, s) | Finds every match | A list of strings (tuples if the pattern has groups) |
re.search(pat, s) | Finds the first match anywhere | A match object, or None |
re.match(pat, s) | Looks only at the start of the string | A match object, or None |
re.fullmatch(pat, s) | The whole string must match | A match object, or None |
re.finditer(pat, s) | Finds every match, one at a time | Match objects, which also give the position |
re.sub(pat, repl, s) | Replaces every match | A new string |
re.split(pat, s) | Splits the string wherever the pattern matches | A list of strings |
re.compile(pat) | Prepares a pattern once, so you can use it many times | A pattern object |
DATE = re.compile(r"\d{4}-\d\d-\d\d") print(DATE.search(s).group()) # 2026-03-14
setup added so this can run · re-runs 2 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
2. Character classes
A character class matches one character from a set.
| Pattern | Matches |
|---|---|
\d | one digit |
\w | one word character: a letter, a digit or _ |
\s | one whitespace character: a space, a tab or a new line |
\D, \W, \S | one character that is NOT a digit, NOT a word character, or NOT whitespace |
[aeiou] | one of the characters inside the brackets |
[a-z] | one character in the range a to z |
[^a-z] | one character that is NOT in the brackets (^ first means "not") |
. | any one character, except a new line |
print(re.findall(r"\w+", "it's ok_2")) # ['it', 's', 'ok_2'] print(re.findall(r"[aeiou]", "regex")) # ['e', 'e'] print(re.findall(r"[^a-z ]", "ab C1")) # ['C', '1'] print(re.findall(r"a.c", "abc a-c ac")) # ['abc', 'a-c'] print(re.findall(r"\.", "v1.2.3")) # ['.', '.']
setup added so this can run · re-runs 3 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
To match a real dot, escape it with a backslash: \..
3. How many
A quantifier after a character or group says how many times it may repeat.
| Pattern | Means |
|---|---|
+ | one or more |
* | zero or more |
? | zero or one: the item is optional |
{3} | exactly three |
{2,3} | two to three |
{2,} | two or more |
print(re.findall(r"lo+l", "ll lol loool")) # ['lol', 'loool'] print(re.findall(r"lo*l", "ll lol")) # ['ll', 'lol'] print(re.findall(r"colou?r", "color colour")) # ['color', 'colour'] print(re.findall(r"\d{3}", "12345678")) # ['123', '456'] print(re.findall(r"\d{2,3}", "12345678")) # ['123', '456', '78']
setup added so this can run · re-runs 4 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Quantifiers are greedy: they take as much text as they can. Add ? after them to make them lazy, so they take as little as they can:
print(re.findall(r"<.+>", "<a><b>")) # ['<a><b>'] print(re.findall(r"<.+?>", "<a><b>")) # ['<a>', '<b>']
setup added so this can run · re-runs 5 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
4. Anchors
An anchor matches a position, not a character.
print(bool(re.search(r"^\d+$", "2026"))) # True print(re.findall(r"\bcat\b", "cat concat cat.")) # ['cat', 'cat'] print(re.findall(r"^\w+", "a b\nc d", re.M)) # ['a', 'c']
setup added so this can run · re-runs 6 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
^ is the start of the string and $ is the end, so ^\d+$ checks the whole string. \b is a word boundary, the edge of a word, so \bcat\b finds only the whole word "cat". With the re.M flag, ^ and $ work on each line.
5. Groups
Parentheses ( ) capture part of the match, so you can read it on its own. Groups are numbered from 1, and group 0 is the whole match.
m = re.search(r"(\w+)@(\S+)", s) print(m.group(1), m.group(2)) # ada dev.io print(m.group(0)) # ada@dev.io print(re.findall(r"(\d+)-(\d+)", "1-2 3-4")) # [('1', '2'), ('3', '4')] print(re.findall(r"(?:ab)+", "abab x ab")) # ['abab', 'ab'] print(re.findall(r"cat|dog", "cat, dog, cow")) # ['cat', 'dog'] print(re.findall(r"(\w)\1", "book keeper")) # ['o', 'e']
setup added so this can run · re-runs 7 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) s = _AutoMock('s') re = _AutoMock('re') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
When a pattern has groups, findall returns only the text of the groups: a string for each match with one group, or a tuple for each match with several groups. (?: ) groups without capturing. | matches either side. \1 matches the same text that group 1 matched, so (\w)\1 finds a doubled letter.
6. Named groups
(?P<name>...) gives a group a name, which is easier to read than a number.
m = re.search(r"(?P<y>\d+)-(?P<m>\d+)", s) print(m["y"]) # 2026 print(m.group("y")) # 2026 print(m.groupdict()) # {'y': '2026', 'm': '03'}
setup added so this can run · re-runs 8 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) s = _AutoMock('s') re = _AutoMock('re') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
7. Look around
A lookaround checks the text next to a match without making it part of the match.
print(re.findall(r"\d+(?=px)", "10px 2em 5px")) # ['10', '5'] print(re.findall(r"(?<=\$)\d+", "$5 and 7")) # ['5'] print(re.findall(r"\b\d+\b(?!%)", "5% 7")) # ['7']
setup added so this can run · re-runs 9 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
| Pattern | Means |
|---|---|
(?=px) | must be followed by px |
(?!%) | must not be followed by % |
(?<=\$) | must come after $ |
(?<!\$) | must not come after $ |
8. Replace
print(re.sub(r"\s+", " ", "a b\n c")) # a b c print(re.sub(r"(\w+)-(\w+)", r"\2-\1", "a-b")) # b-a print(re.sub(r"(?P<d>\d)", r"[\g<d>]", "a1")) # a[1] print(re.sub(r"\d", lambda m: m[0] * 2, "a1")) # a11 print(re.sub(r"o", "0", "foo", count=1)) # f0o
setup added so this can run · re-runs 10 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
In the replacement, \1 and \2 put the groups back, and \g<name> puts back a named group. If you pass a function instead of a replacement string, re.sub calls the function with each match, and the function returns the replacement text. count=1 replaces only the first match.
9. Flags
A flag changes how the whole pattern works. Combine flags with |, for example re.I | re.M.
| Flag | Effect |
|---|---|
re.I | Ignore upper and lower case |
re.M | ^ and $ match at the start and end of each line |
re.S | . also matches a new line |
re.X | Spaces and # comments in the pattern are ignored, so you can spread a long pattern over several lines |
re.A | \w, \d and \s match only ASCII characters |
print(re.findall(r"py", "Py PY", re.I)) # ['Py', 'PY'] print(re.findall(r"(?i)py", "Py")) # ['Py'] print(re.findall(r"a.b", "a\nb", re.S)) # ['a\nb'] PHONE = re.compile(r""" (?P<area>\d{3}) - # area code (?P<num>\d{4}) # local number """, re.X) print(PHONE.search("dial 415-9000").groupdict()) # {'area': '415', 'num': '9000'}
setup added so this can run · re-runs 11 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
(?i) at the start of a pattern sets the flag inside the pattern itself.
10. Useful patterns
These are loose patterns: good for finding things in text, not for strictly checking that input is valid.
print(re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", s)) # ['ada@dev.io'] print(re.findall(r"-?\d+(?:\.\d+)?", "-3.5 2")) # ['-3.5', '2'] print(re.findall(r"\d{4}-\d{2}-\d{2}", s)) # ['2026-03-14'] print(re.findall(r"https?://\S+", "x http://a")) # ['http://a'] print(re.findall(r"#[0-9A-Fa-f]{6}", "red #FF0000")) # ['#FF0000'] print(re.sub(r"<[^>]+>", "", "<b>hi</b>")) # hi
setup added so this can run · re-runs 12 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) s = _AutoMock('s') re = _AutoMock('re') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', 'print(re.findall(r"py", "Py PY", re.I)) # [\'Py\', \'PY\']\nprint(re.findall(r"(?i)py", "Py")) # [\'Py\']\nprint(re.findall(r"a.b", "a\\nb", re.S)) # [\'a\\nb\']\n\nPHONE = re.compile(r"""\n (?P<area>\\d{3}) - # area code\n (?P<num>\\d{4}) # local number\n""", re.X)\nprint(PHONE.search("dial 415-9000").groupdict()) # {\'area\': \'415\', \'num\': \'9000\'}', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Common mistakes
Calling .group() on no match. When nothing matches, re.search() returns None, and None.group() raises AttributeError. Check first:
if m := re.search(r"\d+", s): print(m.group()) # 66
setup added so this can run · re-runs 13 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) s = _AutoMock('s') re = _AutoMock('re') m = _AutoMock('m') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', 'print(re.findall(r"py", "Py PY", re.I)) # [\'Py\', \'PY\']\nprint(re.findall(r"(?i)py", "Py")) # [\'Py\']\nprint(re.findall(r"a.b", "a\\nb", re.S)) # [\'a\\nb\']\n\nPHONE = re.compile(r"""\n (?P<area>\\d{3}) - # area code\n (?P<num>\\d{4}) # local number\n""", re.X)\nprint(PHONE.search("dial 415-9000").groupdict()) # {\'area\': \'415\', \'num\': \'9000\'}', 'print(re.findall(r"[\\w.+-]+@[\\w-]+\\.[\\w.]+", s)) # [\'ada@dev.io\']\nprint(re.findall(r"-?\\d+(?:\\.\\d+)?", "-3.5 2")) # [\'-3.5\', \'2\']\nprint(re.findall(r"\\d{4}-\\d{2}-\\d{2}", s)) # [\'2026-03-14\']\nprint(re.findall(r"https?://\\S+", "x http://a")) # [\'http://a\']\nprint(re.findall(r"#[0-9A-Fa-f]{6}", "red #FF0000")) # [\'#FF0000\']\nprint(re.sub(r"<[^>]+>", "", "<b>hi</b>")) # hi', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Using match to search. re.match() only tries the start of the string. re.match(r"\d+", s) is None because s starts with "Order". Use re.search().
An unescaped dot. . matches any character, so r"\d+.\d+" also matches "1x5". Write \. for a real dot.
Groups change what findall returns. With one group, you get only the group's text:
print(re.findall(r"(\d+)px", "5px 9px")) # ['5', '9'] print(re.split(r"(,)", "a,b")) # ['a', ',', 'b']
setup added so this can run · re-runs 14 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') m = _AutoMock('m') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', 'print(re.findall(r"py", "Py PY", re.I)) # [\'Py\', \'PY\']\nprint(re.findall(r"(?i)py", "Py")) # [\'Py\']\nprint(re.findall(r"a.b", "a\\nb", re.S)) # [\'a\\nb\']\n\nPHONE = re.compile(r"""\n (?P<area>\\d{3}) - # area code\n (?P<num>\\d{4}) # local number\n""", re.X)\nprint(PHONE.search("dial 415-9000").groupdict()) # {\'area\': \'415\', \'num\': \'9000\'}', 'print(re.findall(r"[\\w.+-]+@[\\w-]+\\.[\\w.]+", s)) # [\'ada@dev.io\']\nprint(re.findall(r"-?\\d+(?:\\.\\d+)?", "-3.5 2")) # [\'-3.5\', \'2\']\nprint(re.findall(r"\\d{4}-\\d{2}-\\d{2}", s)) # [\'2026-03-14\']\nprint(re.findall(r"https?://\\S+", "x http://a")) # [\'http://a\']\nprint(re.findall(r"#[0-9A-Fa-f]{6}", "red #FF0000")) # [\'#FF0000\']\nprint(re.sub(r"<[^>]+>", "", "<b>hi</b>")) # hi', 'if m := re.search(r"\\d+", s):\n print(m.group()) # 66', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
A group in split() keeps the separators in the result.
User text with special characters. In a pattern, + means "one or more". To search for text exactly as the user typed it, use re.escape():
print(re.findall(re.escape("a+b"), "a+b")) # ['a+b']
setup added so this can run · re-runs 15 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') m = _AutoMock('m') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', 'print(re.findall(r"py", "Py PY", re.I)) # [\'Py\', \'PY\']\nprint(re.findall(r"(?i)py", "Py")) # [\'Py\']\nprint(re.findall(r"a.b", "a\\nb", re.S)) # [\'a\\nb\']\n\nPHONE = re.compile(r"""\n (?P<area>\\d{3}) - # area code\n (?P<num>\\d{4}) # local number\n""", re.X)\nprint(PHONE.search("dial 415-9000").groupdict()) # {\'area\': \'415\', \'num\': \'9000\'}', 'print(re.findall(r"[\\w.+-]+@[\\w-]+\\.[\\w.]+", s)) # [\'ada@dev.io\']\nprint(re.findall(r"-?\\d+(?:\\.\\d+)?", "-3.5 2")) # [\'-3.5\', \'2\']\nprint(re.findall(r"\\d{4}-\\d{2}-\\d{2}", s)) # [\'2026-03-14\']\nprint(re.findall(r"https?://\\S+", "x http://a")) # [\'http://a\']\nprint(re.findall(r"#[0-9A-Fa-f]{6}", "red #FF0000")) # [\'#FF0000\']\nprint(re.sub(r"<[^>]+>", "", "<b>hi</b>")) # hi', 'if m := re.search(r"\\d+", s):\n print(m.group()) # 66', 'print(re.findall(r"(\\d+)px", "5px 9px")) # [\'5\', \'9\']\nprint(re.split(r"(,)", "a,b")) # [\'a\', \',\', \'b\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Forgetting the r. In "\bhi" without r, Python turns \b into a backspace character, so the pattern finds nothing. Python 3.12 and later also warn about other invalid escapes such as "\d". Always write r"...".
[A-z] instead of [A-Za-z]. The range from A to z also includes [ \ ] ^ _ and the backtick:
print(re.findall(r"[A-z]", "^_")) # ['^', '_']
setup added so this can run · re-runs 16 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) re = _AutoMock('re') s = _AutoMock('s') m = _AutoMock('m') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import re except Exception: pass _pm_earlier = [ 'import re\n\ns = "Order 66 shipped 2026-03-14 to ada@dev.io"', 'print(re.findall(r"\\d+", s)) # [\'66\', \'2026\', \'03\', \'14\']\nprint(re.search(r"\\d+", s).group()) # 66\nprint(re.match(r"\\d+", s)) # None\nprint(bool(re.fullmatch(r"\\d{4}", "2026"))) # True\nprint(re.sub(r"\\d", "#", "a1b22")) # a#b##\nprint(re.split(r"[,;]\\s*", "a, b;c")) # [\'a\', \'b\', \'c\']\nprint([m.span() for m in re.finditer(r"\\d+", "a1 b22")]) # [(1, 2), (4, 6)]', 'DATE = re.compile(r"\\d{4}-\\d\\d-\\d\\d")\nprint(DATE.search(s).group()) # 2026-03-14', 'print(re.findall(r"\\w+", "it\'s ok_2")) # [\'it\', \'s\', \'ok_2\']\nprint(re.findall(r"[aeiou]", "regex")) # [\'e\', \'e\']\nprint(re.findall(r"[^a-z ]", "ab C1")) # [\'C\', \'1\']\nprint(re.findall(r"a.c", "abc a-c ac")) # [\'abc\', \'a-c\']\nprint(re.findall(r"\\.", "v1.2.3")) # [\'.\', \'.\']', 'print(re.findall(r"lo+l", "ll lol loool")) # [\'lol\', \'loool\']\nprint(re.findall(r"lo*l", "ll lol")) # [\'ll\', \'lol\']\nprint(re.findall(r"colou?r", "color colour")) # [\'color\', \'colour\']\nprint(re.findall(r"\\d{3}", "12345678")) # [\'123\', \'456\']\nprint(re.findall(r"\\d{2,3}", "12345678")) # [\'123\', \'456\', \'78\']', 'print(re.findall(r"<.+>", "<a><b>")) # [\'<a><b>\']\nprint(re.findall(r"<.+?>", "<a><b>")) # [\'<a>\', \'<b>\']', 'print(bool(re.search(r"^\\d+$", "2026"))) # True\nprint(re.findall(r"\\bcat\\b", "cat concat cat.")) # [\'cat\', \'cat\']\nprint(re.findall(r"^\\w+", "a b\\nc d", re.M)) # [\'a\', \'c\']', 'm = re.search(r"(\\w+)@(\\S+)", s)\nprint(m.group(1), m.group(2)) # ada dev.io\nprint(m.group(0)) # ada@dev.io\n\nprint(re.findall(r"(\\d+)-(\\d+)", "1-2 3-4")) # [(\'1\', \'2\'), (\'3\', \'4\')]\nprint(re.findall(r"(?:ab)+", "abab x ab")) # [\'abab\', \'ab\']\nprint(re.findall(r"cat|dog", "cat, dog, cow")) # [\'cat\', \'dog\']\nprint(re.findall(r"(\\w)\\1", "book keeper")) # [\'o\', \'e\']', 'm = re.search(r"(?P<y>\\d+)-(?P<m>\\d+)", s)\nprint(m["y"]) # 2026\nprint(m.group("y")) # 2026\nprint(m.groupdict()) # {\'y\': \'2026\', \'m\': \'03\'}', 'print(re.findall(r"\\d+(?=px)", "10px 2em 5px")) # [\'10\', \'5\']\nprint(re.findall(r"(?<=\\$)\\d+", "$5 and 7")) # [\'5\']\nprint(re.findall(r"\\b\\d+\\b(?!%)", "5% 7")) # [\'7\']', 'print(re.sub(r"\\s+", " ", "a b\\n c")) # a b c\nprint(re.sub(r"(\\w+)-(\\w+)", r"\\2-\\1", "a-b")) # b-a\nprint(re.sub(r"(?P<d>\\d)", r"[\\g<d>]", "a1")) # a[1]\nprint(re.sub(r"\\d", lambda m: m[0] * 2, "a1")) # a11\nprint(re.sub(r"o", "0", "foo", count=1)) # f0o', 'print(re.findall(r"py", "Py PY", re.I)) # [\'Py\', \'PY\']\nprint(re.findall(r"(?i)py", "Py")) # [\'Py\']\nprint(re.findall(r"a.b", "a\\nb", re.S)) # [\'a\\nb\']\n\nPHONE = re.compile(r"""\n (?P<area>\\d{3}) - # area code\n (?P<num>\\d{4}) # local number\n""", re.X)\nprint(PHONE.search("dial 415-9000").groupdict()) # {\'area\': \'415\', \'num\': \'9000\'}', 'print(re.findall(r"[\\w.+-]+@[\\w-]+\\.[\\w.]+", s)) # [\'ada@dev.io\']\nprint(re.findall(r"-?\\d+(?:\\.\\d+)?", "-3.5 2")) # [\'-3.5\', \'2\']\nprint(re.findall(r"\\d{4}-\\d{2}-\\d{2}", s)) # [\'2026-03-14\']\nprint(re.findall(r"https?://\\S+", "x http://a")) # [\'http://a\']\nprint(re.findall(r"#[0-9A-Fa-f]{6}", "red #FF0000")) # [\'#FF0000\']\nprint(re.sub(r"<[^>]+>", "", "<b>hi</b>")) # hi', 'if m := re.search(r"\\d+", s):\n print(m.group()) # 66', 'print(re.findall(r"(\\d+)px", "5px 9px")) # [\'5\', \'9\']\nprint(re.split(r"(,)", "a,b")) # [\'a\', \',\', \'b\']', 'print(re.findall(re.escape("a+b"), "a+b")) # [\'a+b\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Very slow patterns. Nested repeats such as (a+)+ can take an extremely long time on some inputs. Keep patterns simple, and avoid a repeat inside a repeat.
See also
- Regex (tutorial)
- Strings cheat sheet
- F-strings cheat sheet for
r""and escape rules
Practice this
on practicepython.inShort exercises that run in your browser and tell you what your code did, as well as whether a test passed.
Found this useful? Share it with a friend who’s learning Python.