Skip to content

Regex Cheat Sheet

PatternMatches
.Any single character (except newline)
\dDigit (0-9)
\DNon-digit
\wWord character (a-z, A-Z, 0-9, _)
\WNon-word character
\sWhitespace (space, tab, newline)
\SNon-whitespace

| | Newline | | \t | Tab | | | Carriage return |

PatternMatches
^Start of string (or line with m flag)
$End of string (or line with m flag)
Word boundary
\BNot a word boundary
\AStart of string (absolute)
\ZEnd of string (absolute)
PatternMatches
*0 or more
+1 or more
?0 or 1 (optional)
{3}Exactly 3
{3,}3 or more
{3,5}Between 3 and 5
*?0 or more (lazy/non-greedy)
+?1 or more (lazy/non-greedy)
??0 or 1 (lazy/non-greedy)
String: <div>hello</div>
Greedy: <.*> matches "<div>hello</div>"
Lazy: <.*?> matches "<div>"
PatternMatches
[abc]a, b, or c
[^abc]Not a, b, or c
[a-z]Lowercase letter
[A-Z]Uppercase letter
[0-9]Digit (same as \d)
[a-zA-Z]Any letter
[a-zA-Z0-9_]Word character (same as \w)
[\s\S]Any character including newline

Inside character classes:

  • Most special characters are literal (no escaping needed)
  • Escape: ], \, ^ (at start), - (in middle)
PatternDescription
(abc)Capturing group
(?:abc)Non-capturing group
(?<name>abc)Named capturing group
\1, \2Backreference to group 1, 2
(?P=name)Backreference by name (Python)
\k<name>Backreference by name (JS, .NET)
# Capture area code from phone number
\((\d{3})\) \d{3}-\d{4}
Input: (415) 555-1234
Group 1: 415
# Named group
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
# Backreference - match repeated words
(\w+)\s+\1
Matches: "the the", "is is"
PatternMatches
a|ba or b
(cat|dog)cat or dog (captured)
(?:cat|dog)cat or dog (not captured)
PatternNameDescription
(?=abc)Positive lookaheadFollowed by abc
(?!abc)Negative lookaheadNot followed by abc
(?<=abc)Positive lookbehindPreceded by abc
(?<!abc)Negative lookbehindNot preceded by abc
# Password: at least one digit, one uppercase, one lowercase
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$
# Match "foo" not followed by "bar"
foo(?!bar)
Matches: "foobaz", "foo "
Skips: "foobar"
# Match number preceded by $
(?<=\$)\d+
Input: "Price: $100"
Matches: "100"
# Match word not preceded by @
(?<!@)word
FlagNameDescription
iCase insensitiveA matches a
gGlobalFind all matches
mMultiline^/$ match line start/end
sDotall. matches newline
xExtendedIgnore whitespace, allow comments
uUnicodeFull Unicode support
(?i)case insensitive
(?i:just this part) rest is case sensitive
(?-i)turn off case insensitive
[\w.-]+@[\w.-]+\.\w{2,}
https?://[^\s/$.?#].[^\s]*
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])
(?:\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}
<([a-z]+)[^>]*>.*?</\1>
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
^[a-z0-9]+(?:-[a-z0-9]+)*$
"(?:[^"\]|\.)*"
//.*|/\*[\s\S]*?\*/
const re = /pattern/flags;
const re = new RegExp('pattern', 'flags');
str.match(re) // Array of matches or null
str.test(re) // Boolean
str.replace(re, 'new')
str.split(re)
re.exec(str) // Detailed match info
// Named groups (ES2018+)
const match = /(?<year>\d{4})/.exec('2024');
match.groups.year // "2024"
import re
re.search(pattern, string) # First match
re.match(pattern, string) # Match at start only
re.findall(pattern, string) # All matches as list
re.finditer(pattern, string) # Iterator of match objects
re.sub(pattern, repl, string) # Replace
re.split(pattern, string) # Split
# Compile for reuse
regex = re.compile(r'pattern', re.IGNORECASE)
regex.search(string)
# Named groups
match = re.search(r'(?P<year>\d{4})', '2024')
match.group('year') # "2024"
Terminal window
grep -E 'pattern' file # Extended regex
grep -P 'pattern' file # Perl regex (GNU grep)
grep -o 'pattern' file # Only matching part
grep -i 'pattern' file # Case insensitive
grep -v 'pattern' file # Invert match
rg 'pattern' file # Rust regex (fast)
rg -i 'pattern' # Case insensitive
rg -o 'pattern' # Only matching part
rg --pcre2 'pattern' # Perl-compatible regex
Terminal window
sed 's/pattern/replacement/' # First match
sed 's/pattern/replacement/g' # All matches
sed -E 's/pattern/replacement/' # Extended regex
sed 's/\(group\)/\1/' # Backreference (BRE)
sed -E 's/(group)/\1/' # Backreference (ERE)
  1. Escape special characters in literals: \. \* \+ \? \[ \] \( \) \{ \} \| \ \^ \$

  2. Use raw strings in Python: r'\d+' not '\d+'

  3. Anchors matter: \d+ matches digits anywhere; ^\d+$ matches only if entire string is digits

  4. Greedy by default: .* eats as much as possible; use .*? for lazy

  5. Character class shortcuts: [0-9] = \d, [a-zA-Z0-9_] = \w, `[

]=\s`

  1. Test incrementally: Build complex patterns piece by piece

  2. Use non-capturing groups (?:...) when you don’t need the match

  3. Catastrophic backtracking: Avoid nested quantifiers like (a+)+ on long strings

  • Shell — grep, sed, awk patterns that use regex
  • CLI Pipelines — Text processing with pipes
  • Pythonre module usage
  • Regex Lesson Plan — 8 lessons from literals to lookahead and extraction
  • jq — JSON filtering with regex tests