← All cheatsheets
All paths · #039 · August 31, 2026 · 1 min read

How much regex do you need for data work?

Anchors, classes, quantifiers, groups, four patterns to steal, and how to use them from pandas and SQL: the 20 regex pieces that cover 99% of data cleaning.

Get the free PDF

One page, print-ready, free to share. No signup needed.

Download the PDF

Regex is a write-only language: nobody remembers it, everybody needs it. These 20 pieces cover 99% of data-cleaning work, and the same patterns run in Python, pandas and SQL. The print-ready A4 PDF is at the bottom.

Anchors and classes

  • ^start / end$: the edges of the string.
  • \d \w \s: digit, word character, whitespace.
  • .: any single character.
  • [A-Za-z]: build your own class.

Quantifiers

  • + / *: one-or-more / zero-or-more.
  • ?: optional.
  • {2,4}: between 2 and 4 repeats.
  • .*: greedy. Eats everything it can.

Groups

  • (abc): capture it.
  • (?:abc): group without capturing.
  • a|b: or.
  • \1: reuse capture 1.

Patterns to steal

  • \d{4}-\d{2}-\d{2}: ISO date.
  • [\w.]+@[\w.]+\.\w+: email-ish.
  • \d+[.,]\d+: decimal number.
  • \s{2,}: runs of extra spaces.

In pandas

  • s.str.contains(r'…'): filter rows.
  • s.str.extract(r'(…)'): pull the group into a column.
  • s.str.replace(r'…',''): clean.

In SQL

  • x ~ 'regex': Postgres match.
  • REGEXP_LIKE(x, r): most other dialects.
  • REGEXP_REPLACE(x, r, ''): clean in place.

Columns out of chaos

# "order #4521 shipped 2026-08-12 (US)"
s = df["raw"]
df["order_id"] = s.str.extract(r"#(\d+)")
df["date"] = s.str.extract(r"(\d{4}-\d{2}-\d{2})")
df["country"] = s.str.extract(r"\((\w{2})\)")

extract returns whatever the (group) captures. One pattern per concept beats one giant pattern.

The trap: greedy by default

PatternOn this inputIt matches
<b>(.*)</b><b>a</b> <b>b</b>a</b> <b>b : too much
<b>(.*?)</b><b>a</b> <b>b</b>a : lazy stops early
^\d+$abc123nothing: anchors save you

Add ? after * or + to make it lazy, and anchor with ^ $ whenever you mean the whole string.

Frequently asked questions

What regex do I need to extract dates from text?
For ISO dates, \d{4}-\d{2}-\d{2}: four digits, dash, two digits, dash, two digits. In pandas: s.str.extract(r'(\d{4}-\d{2}-\d{2})'). Wrap the part you want in parentheses: extract returns whatever the group captures.
What is the difference between greedy and lazy matching?
Quantifiers are greedy by default: .* eats as much as it can while still allowing a match, so <b>(.*)</b> on a string with two bold tags captures everything between the FIRST opening and the LAST closing tag. Adding ? makes it lazy: (.*?) stops at the first closing tag.
Can I use regex in SQL?
Yes. Postgres matches with the ~ operator (x ~ 'regex'), most other dialects have REGEXP_LIKE(x, r), and REGEXP_REPLACE(x, r, '') cleans in place. Same patterns, same syntax core as Python.
How do I use regex in pandas?
Three string methods cover most needs: s.str.contains(r'…') to filter rows, s.str.extract(r'(…)') to pull a captured group into a new column, s.str.replace(r'…', '') to clean. All three take the same patterns as this sheet.

Get the free PDF

One page, print-ready, free to share. No signup needed.

Download the PDF

More cheatsheets