Regexdrill

Regexdrill / Cheat sheet

Regex cheat sheet

Every token you will meet, then the working patterns for the jobs that come up (validation, extraction, cleanup, log parsing) in the JavaScript, Python and PCRE flavors with the differences marked. Most entries have a drill that tests your pattern on real strings. Print the page or get the PDF by email.

No newsletter spam: the PDF, one follow-up with the free exercises, and nothing else unless you ask.

The ones worth learning first

WhatHow
Any digit, any word character, any space\d \w \s (capitals negate: \D \W \S)
One or more, zero or more, optional+ * ?
Exactly n, between n and m{3} {2,5}
Start and end of the string^...$
A set, a range, not in the set[aeiou] [a-z0-9] [^0-9]
Eithercat|dog (group it: (cat|dog)s?)
Capture a part(\d{4})-(\d{2}) $1 or \1 to reuse
Lazy instead of greedy.*? .+?
Followed by / not followed by(?=...) (?!...)
Ignore case, all matches/pattern/gi re.I (?i)

Characters

Literal textcat drill
Any character except newlineWith the s flag (dotall) it also matches newlines.. drill
Escape a special characterSpecials: . * + ? ^ $ ( ) [ ] { } | \ /\. \? \( \[ \\ \$ drill
Digit\d (same as [0-9])
Word character\w (letters, digits, underscore)
Whitespace\s (space, tab, newline)
Not a digit / word / space\D \W \S
Tab, newline\t \n \r
Unicode letter\p{L} (JavaScript needs the u flag) drill

Classes

One of a set[aeiou] drill
Range[a-z] [A-Z0-9] [a-zA-Z] drill
Not in the set[^0-9] [^\s] drill
Literal hyphen or bracket inside a classPut the hyphen first or last.[-a-z] [a-z\]]
Hex digit[0-9a-fA-F] drill
Common pairs[\w.-] for emails and slugs

Quantifiers

Zero or morea* drill
One or morea+ drill
Optionalcolou?r drill
Exactly n\d{4}
At least n\d{2,}
Between n and m\d{2,5}
Greedy by default<.+> matches the whole <a><b>
Lazy<.+?> matches <a> then <b> drill
Possessive (PCRE, Java)a++ (no backtracking)

Anchors and boundaries

Start, end of string^abc$ drill
Per line^...$ with the m flag drill
Word boundary\bcat\b matches cat, not concat drill
Not a boundary\B
Absolute start and end (Python, PCRE)\A \Z

Groups and alternation

Eithercat|dog drill
Either, anchoredWithout the group, ^cat|dog$ means (^cat)|(dog$).^(cat|dog)$ drill
Capture group(\d{4})-(\d{2})-(\d{2}) drill
Non-capturing group(?:https?|ftp):// drill
Named group(?<year>\d{4}) Python: (?P<year>\d{4}) drill
Backreference(\w)\1 matches a doubled letter drill
Matching quotes(["'])(.*?)\1 drill
Optional group(\+1 )?\d{3}-\d{4} drill
Repeated group(\d{1,3}\.){3}\d{1,3} drill
Replacement referencesJavaScript: $1 $<name> Python: \1 \g<name>

Lookarounds

Followed by\d+(?= dollars) drill
Not followed by\d+(?! dollars) drill
Preceded by(?<=\$)\d+ drill
Not preceded by(?<!\$)\b\d+ drill
Password rules (several lookaheads)^(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$ drill
Thousands separators\B(?=(\d{3})+(?!\d)) replace with ,

Flags

Ignore case/x/i re.IGNORECASE (?i)x
All matches/x/g Python: re.findall / re.sub (always all)
Multiline anchors/x/m re.MULTILINE
Dot matches newline/x/s re.DOTALL
Unicode/x/u (Python 3 strings are Unicode by default)
Verbose (comments and spaces)re.VERBOSE (?x)

Validation patterns

Email (practical)Full RFC validation is not worth it; send a confirmation email.^[\w.+-]+@[\w-]+(\.[\w-]+)+$ drill
US ZIP^\d{5}(-\d{4})?$ drill
Phone (flexible)^\+?\d{1,3}?[-. ]?\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$ drill
ISO date^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ drill
24-hour time^([01]\d|2[0-3]):[0-5]\d$ drill
12-hour time^(1[0-2]|0?[1-9]):[0-5]\d ?[AaPp][Mm]$ drill
IPv4^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$ drill
URL slug^[a-z0-9]+(-[a-z0-9]+)*$ drill
SKU like AB-1234^[A-Z]{2}-\d{4}$ drill
Money^\$?\d{1,3}(,\d{3})*(\.\d{2})?$ drill
Hex color^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
UUID^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$

Extraction and cleanup

Numbers from text\d+(\.\d+)? drill
Dates in text\b\d{4}-\d{2}-\d{2}\b drill
Domain from an email or URL@([\w.-]+) or https?://([^/]+) drill
Hashtags#\w+ drill
Key=value pairs(\w+)=("[^"]*"|\S+) drill
Log line^(\S+) (\S+) \[([^\]]+)\] "(\w+) ([^"]+)" (\d{3}) drill
CSV field (quoted or not)"([^"]*)"|([^,]+) drill
Trim both ends^\s+|\s+$ replace with nothing drill
Collapse spaces\s{2,} replace with one space drill
Strip HTML tagsFine for cleanup, not for parsing HTML.<[^>]+> drill
Capitalized names\b[A-Z][a-z]+ [A-Z][a-z]+\b drill
Units after a number(\d+(?:\.\d+)?)\s?(kg|g|lb|oz)\b drill
Titles\b(Mr|Mrs|Ms|Dr)\.?\s drill
Keep only digitsreplace [^0-9] with nothing

In code

JavaScript test/^\d+$/.test(s)
JavaScript all matches[...s.matchAll(/(\w+)=(\d+)/g)]
JavaScript replace with groupss.replace(/(\d{4})-(\d{2})/g, '$2/$1')
Python match at startre.match(r'^\d+', s)
Python search anywherere.search(r'\d+', s)
Python allre.findall(r'\d+', s) re.finditer(...)
Python replacere.sub(r'\s+', ' ', s)
Python compile oncepat = re.compile(r'...'); pat.search(s)
pandasdf['col'].str.extract(r'(\d+)') .str.contains(r'^A', regex=True)
SQLPostgreSQL: col ~ '^\d+$' MySQL: col REGEXP '^[0-9]+$'
Raw stringsPython r'...' and JavaScript String.raw avoid double escaping.

regexdrill.com: practice every one of these with instant checking. 88 entries.

Questions

Why does my pattern match too much?

Quantifiers are greedy: .* takes everything it can and then backs off. Use a lazy quantifier (.*?) or, better, a negated class that cannot cross the boundary you care about, such as [^"]* inside quotes.

Why does ^cat|dog$ match 'hotdog'?

Alternation has the lowest precedence, so the pattern reads as (^cat) or (dog$). Group the alternatives: ^(cat|dog)$.

Should I validate emails with regex?

Only loosely. A practical pattern catches typos; the only real validation is sending a message to the address.

JavaScript, Python or PCRE: which flavor is this?

The tokens are common to all three. Differences that matter are marked: named groups ((?<n>) vs (?P<n>)), replacement references ($1 vs \1), the u flag for Unicode classes in JavaScript, and \A \Z which JavaScript does not have.

How do I match across lines?

Use the s (dotall) flag so . matches newlines, or [\s\S] in place of the dot. For per-line anchors use the m flag.

A cheat sheet does not make them stick

Doing them with instant checking does. The free exercises need no account.

Start practicing