Python regular expression patterns matching structured text

Python Regex Cheatsheet: Practical Patterns for Everyday Text

Regular expressions are easiest to learn when you connect each pattern to a real task. In Python, the re module gives you the basic tools: find, validate, capture, split, and replace.

Start with this mental model: a regex does not describe what a string “means”. It describes the shape of text you want to match.

1. Import re and use raw strings

Always write regex patterns as raw strings with r"...". It keeps backslashes readable and avoids accidental Python string escapes.

import re

text = "Order #A-1042 ships on 2026-08-19"
match = re.search(r"#([A-Z]-\d+)", text)

if match:
    print(match.group(1))  # A-1042

2. Common building blocks

Here are the pieces you will reuse constantly:

Pattern Meaning Example match
\d digit 7
\w word character a, Z, _, 3
\s whitespace space, tab, newline
. any character except newline x
+ one or more aaa
* zero or more empty or aaa
? optional empty or one
{2,4} between 2 and 4 times 12, 1234
^ start of string start only
$ end of string end only

3. Validate a simple email shape

Email validation can get extremely complicated. For product forms, you usually want a practical first-pass check, not the entire email RFC.

import re

pattern = r"^[\w.+-]+@[\w-]+(?:\.[\w-]+)+$"

emails = [
    "ada@example.com",
    "first.last+tag@sub.example.co",
    "not-an-email",
]

for email in emails:
    print(email, bool(re.fullmatch(pattern, email)))

Use fullmatch() when the whole string must match. Use search() when the pattern may appear anywhere inside a larger string.

4. Capture dates

Parentheses create capture groups. They let you extract the parts you care about.

import re

text = "Published: 2026-08-19"
match = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)

if match:
    year, month, day = match.groups()
    print(year, month, day)

Named groups are clearer when a pattern grows:

import re

pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
match = re.search(pattern, "Published: 2026-08-19")

if match:
    print(match.groupdict())

5. Extract all matching values

Use findall() for simple extraction and finditer() when you also need positions or named groups.

import re

text = "Errors: E100, E203, E404"
print(re.findall(r"E\d{3}", text))

for match in re.finditer(r"E\d{3}", text):
    print(match.group(), match.start(), match.end())

6. Replace messy whitespace

re.sub() is perfect for cleanup tasks.

import re

raw = "Python     regex\ncan\tclean   text"
clean = re.sub(r"\s+", " ", raw).strip()

print(clean)  # Python regex can clean text

You can also use capture groups inside replacements:

import re

text = "2026/08/19"
iso = re.sub(r"(\d{4})/(\d{2})/(\d{2})", r"\1-\2-\3", text)

print(iso)  # 2026-08-19

7. Split on flexible separators

When data comes from humans, separators are rarely consistent.

import re

text = "python, regex; parsing | cleanup"
parts = re.split(r"\s*[,;|]\s*", text)

print(parts)  # ['python', 'regex', 'parsing', 'cleanup']

8. Use non-capturing groups for structure

If you need grouping but do not need to extract that group, use (?:...).

import re

pattern = r"https?://(?:www\.)?example\.com/\w+"
print(bool(re.search(pattern, "Visit https://www.example.com/docs")))

That keeps match.groups() focused on values you actually want.

9. Make patterns readable with re.VERBOSE

Long regexes become much easier to maintain when you spread them over multiple lines and add comments.

import re

phone_pattern = re.compile(r"""
    ^
    \+?              # optional country prefix
    \d{1,3}?         # country code
    [\s.-]?
    \(?\d{2,4}\)?   # area code
    [\s.-]?
    \d{3,4}
    [\s.-]?
    \d{4}
    $
""", re.VERBOSE)

print(bool(phone_pattern.fullmatch("+1 415 555 0133")))

10. Compile patterns you reuse

For one-off checks, calling re.search() directly is fine. For repeated matching, compile the pattern once.

import re

slug_re = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")

for slug in ["python-regex", "Bad Slug", "notes-2026"]:
    print(slug, bool(slug_re.fullmatch(slug)))

A small checklist

  • Use raw strings: r"\d+"
  • Prefer fullmatch() for validation
  • Prefer named groups for important captures
  • Use finditer() when you need match positions
  • Use re.VERBOSE for patterns that future-you must read
  • Keep validation regexes practical unless you truly need a full specification

Regex becomes less mysterious once you stop trying to memorize everything. Learn the small pieces, combine them carefully, and test each pattern against real examples.