Skip to main content
Intermediate Python2026-07-31 · 11 min read

Python Regex Explained (2026)

Regex is Python's most feared feature. It's not that hard — but 80% of tutorials front-load the theory (\d, \w, greedy vs lazy) before showing you a single pattern you'd actually use in real code. This tutorial flips that.

We'll cover: the re module basics, the five patterns that cover 90% of real work, when re.compile actually helps, named groups vs numbered, and the four cases where regex is the WRONG tool.

The module in 60 seconds

Everything lives in the stdlib re module. Three functions cover most needs:

▶ PYTHONeditable · runs in your browser

Rule: use re.search when in doubt. re.match only checks the start; forgetting that leads to "my regex doesn't match!" 30 minutes lost.

Raw strings — always use them

r"..." prefix disables backslash interpretation. Without it, "\d" becomes "\\d" in Python, which the regex engine sees as \d — same result, but only by accident and only for \d. "\n" in a regex is a newline, not the two chars \ + n.

▶ PYTHONeditable · runs in your browser

Muscle memory: every regex literal starts with r. No exceptions.

The 5 patterns that cover 90% of real work

1. Extract all integers from text

▶ PYTHONeditable · runs in your browser

Note 199.99 splits into ['199', '99']\d+ doesn't cross the dot. Use r"\d+(?:\.\d+)?" for optional decimals:

▶ PYTHONeditable · runs in your browser

2. Normalise whitespace

▶ PYTHONeditable · runs in your browser

\s+ matches any run of spaces / tabs / newlines. Replace with a single space, strip the edges. This is Python's answer to sed -E 's/[[:space:]]+/ /g'.

3. Extract the hostname from a URL

▶ PYTHONeditable · runs in your browser

The parentheses create a capture group; .group(1) returns its content. [^/:]+ = "one or more chars that aren't / or :" — stops at the port separator OR the path.

For production URL parsing use urllib.parse.urlparse (handles edge cases like userinfo + IPv6). Regex is for quick-and-dirty extraction.

4. Loose email validation

There is NO regex that fully validates emails per RFC 5322. Anyone who tells you otherwise is selling something. But this one catches 99% of real addresses without false-rejecting good ones:

▶ PYTHONeditable · runs in your browser

Anchors (^ and $) force full-string match. Without them, "foo@bar" inside a bigger sentence would match.

Production: send a confirmation email. That's the ONLY reliable email validator.

5. Named capture groups

Numbered groups ((...) + .group(1)) are fine for 2-3 captures. Beyond that, names win:

▶ PYTHONeditable · runs in your browser

.groupdict() returns a dict of all named groups. Add / reorder groups without breaking every call-site that referred to .group(3).

re.compile — when it actually helps

▶ PYTHONeditable · runs in your browser

The stdlib maintains a small compiled-pattern cache (default size 512), so one-off re.search(pattern, text) calls are effectively free after the first hit. re.compile explicitly helps when:

1. The pattern is used inside a tight loop (millions of matches).

2. You want to store the pattern as a module-level constant for grep-ability.

3. You need .finditer(), .pattern, .flags on the compiled object.

Don't over-compile. Every module-level re.compile adds a tiny import-time cost.

Common flags

▶ PYTHONeditable · runs in your browser

Combine with |: re.IGNORECASE | re.MULTILINE.

When regex is the WRONG tool

1. Parsing HTML / XML → use a real parser

▶ PYTHONeditable · runs in your browser

The classic Stack Overflow answer for this is 20 years old and still true.

2. Parsing JSON → use json

The json module handles nested quotes, escaped chars, Unicode, and every RFC 8259 edge case. Regex-parsing JSON is an anti-pattern signal.

3. Parsing dates → use dateutil or datetime.strptime

dateutil.parser.parse("2026-07-30") accepts every format a human might type. datetime.strptime handles known formats efficiently. Both handle timezones. Regex would need to reinvent all of it.

4. Nested / recursive patterns → use a parser generator

Matched-parens, nested JSON, balanced expressions are formally beyond regex's power (context-free grammar territory). Use pyparsing / lark / ANTLR — or just walk the string with a small parser.

Debugging regex

Use regex101.com (choose "Python" flavour). Paste the pattern + sample text; it highlights matches in real time, explains every metacharacter, and shows named groups. Fastest way to learn regex intuitively.

For code-level debugging, re.DEBUG prints the compiled state machine:

▶ PYTHONeditable · runs in your browser

Practice

Write a regex for each. Solutions below.

1. Extract the version number from "Python 3.13.2 (main, Jan 15 2026, 10:32:11)" — should return "3.13.2".

2. Split "apple,banana; cherry orange" on any delimiter (,, ;, or space).

3. Rewrite foo.bar_baz-123 as FOO.BAR_BAZ-123 (uppercase letters only, leave digits and punctuation).

Solutions:

▶ PYTHONeditable · runs in your browser

Regex is a superpower once you're past the first 10 patterns. The trick is to build muscle memory on the five above — they cover 90% of real work. Reach for a real parser the moment you find yourself writing backreferences to balance parens.

Next step: regex + text-processing lessons in the Automation track — practise on log files, CSV data, and web-scraping tasks with real Python running in your browser.

Ready to try it?

15 lessons free after a free signup — no card. Sample the platform, then decide.

Start free

Or unlock every lesson

Pro — $12/mo, unlimited AI, cancel any time. Refund within 14 days worldwide.

See Pro plans

Get one Python lesson + one career idea every Friday

No spam, no "buy our course now". Three bullets, every Friday. Unsubscribe with one click.