Regular Expressions Cheatsheet
Alternation
Use this Regular Expressions reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
The | operator
| splits the pattern into alternatives and has the lowest precedence of every regex operator, so it stretches as far left and right as it can.
| Pattern | Reads as |
|---|---|
^cat|dog$ | (^cat) or (dog$) |
^(?:cat|dog)$ | start, then cat or dog, then end |
gray|grey | two whole words |
gr(?:a|e)y | same thing, one shared prefix |
abc| | abc or the empty string, always matches |
import re re.findall(r'^a|b$', 'ab') # ['a', 'b'], two separate matches re.search(r'(?:^a|b)$', 'ab') # matches 'b' only
Always wrap an alternation in (?:...) when it sits inside a larger pattern. The bug of forgetting is silent, the regex still compiles and still matches something.
Order matters in backtracking engines
Perl-style engines (JavaScript, Python, PCRE, Java, .NET, Ruby, and Go's default) are leftmost-first. They try alternatives left to right and stop at the first one that lets the whole pattern succeed.
re.search(r'cat|category', 'category').group() # 'cat' re.search(r'category|cat', 'category').group() # 'category'
Put the longest or most specific alternative first when the alternatives share a prefix. Anchors also fix it, because a failing anchor forces the engine on to the next branch.
re.search(r'\b(cat|category)\b', 'category').group() # 'category'
POSIX tools are leftmost-longest instead
grep -E, awk, and sed pick the longest match at the leftmost position, so alternative order does not change the result.
echo category | grep -Eo 'cat|category' # category echo category | awk '{ match($0, /cat|category/) print substr($0, RSTART, RLENGTH) }' # category
Go is leftmost-first by default and only switches with an explicit opt-in.
regexp.MustCompile(`cat|category`).FindString("category") // "cat" p := regexp.MustCompilePOSIX(`cat|category`); p.Longest() p.FindString("category") // "category"
Alternation in BRE
Plain grep and BSD sed use BRE, where there is no alternation at all. GNU tools add \| as an extension, BSD tools do not.
| Tool | Alternation |
|---|---|
grep -E / egrep | | |
grep (BRE, GNU) | | |
grep (BRE, BSD/macOS) | none, use -E |
GNU sed | | in BRE, | with -E |
BSD sed (macOS) | none in BRE, | with -E |
awk | |, always ERE |
Portable answer: pass -E and use bare |. Both GNU and BSD accept -E, and POSIX blesses it.
Building an alternation of literals
For a list of fixed words, a shared prefix plus anchors beats a flat list.
\b(?:cat|dog|bird)\b fine for a handful \b(?:jan|feb|mar|apr|may|jun)\b fine, all same length (?:https?|ftp|file):// shared suffix outside the group
- Sort so no alternative is a prefix of a later one, or anchor with
\b. - Escape every literal you interpolate.
re.escapein Python,regexp.QuoteMetain Go,Pattern.quotein Java. - Above roughly a few dozen literals, stop. A set lookup or
grep -F -f wordlistis faster and cannot be broken by a stray metacharacter.
# fixed-string search over a word list, no regex engine involved
grep -F -f words.txt access.logEmpty and overlapping alternatives
An empty branch makes the whole group optional and can produce zero-width matches everywhere.
| Risky | Meaning | Better |
|---|---|---|
(a|b|) | a, b, or nothing | (?:a|b)? |
(?:x|)+ | can loop on empty | x* |
(a|a) | duplicate work on failure | a |
(.*|\d+) | second branch unreachable | pick one |
Duplicate or overlapping branches are the raw material for catastrophic backtracking, because on failure the engine retries the same span through every branch. (a|a)*$ against a long run of a followed by b is the classic exponential case.