A quick-reference for regex syntax. Regular expressions are
patterns for matching and manipulating text. The core syntax is
consistent across most tools โ Python's re,
JavaScript's RegExp, grep -E,
sed, and PCRE all share the same fundamentals, with
minor differences in supported features.
Most characters match themselves literally. A handful of
characters โ . ^ $ * + ? { } [ ] \ | ( ) โ are
special and must be escaped with \ to be treated as
literals.
Dot (.):
Matches any single character except a newline. Use the s flag to make it match newlines too.
Literal characters:
Any non-special character matches itself. cat matches the string "cat" exactly.
abc # literal "abc"
a.c # "a" + any char + "c" โ "abc", "a1c", "a c"
a\.c # literal "a.c" (escaped dot)
a|b # "a" OR "b"
(ab)+ # one or more repetitions of "ab"
Quantifiers apply to the preceding element (character, group, or
class). By default they are greedy โ they match
as much as possible. Append ? to make them
lazy โ match as little as possible.
* zero or more colou*r โ "colour", "colouur", "colr"
+ one or more colou+r โ "colour", "colouur" (not "colr")
? zero or one colou?r โ "colour", "colr"
{n} exactly n \d{4} โ exactly 4 digits
{n,} n or more \d{2,} โ 2 or more digits
{n,m} between n and m \d{2,4} โ 2, 3, or 4 digits
<.+> greedy โ matches "<b>bold</b>" (entire string)
<.+?> lazy โ matches "<b>" then "</b>" separately
(lazy quantifiers stop at the earliest possible match)
A character class matches one character from a defined set.
Shorthands like \d are equivalent to their bracket
form but more concise.
[abc] matches a, b, or c
[^abc] matches anything except a, b, c
[a-z] lowercase letter
[A-Za-z0-9] alphanumeric
[a-z&&[^aeiou]] consonants (Java-style intersection)
\d digit [0-9]
\D non-digit [^0-9]
\w word character [a-zA-Z0-9_]
\W non-word [^a-zA-Z0-9_]
\s whitespace [ \t\n\r\f]
\S non-whitespace
\b word boundary (zero-width, see Anchors)
. any char except newline (see Basics)
Anchors are zero-width โ they match a position, not a character. They don't consume input.
^ start of string (or line in multiline mode)
$ end of string (or line in multiline mode)
\b word boundary: between \w and \W
\B non-word boundary
\A start of string (Python/Perl; ignores multiline flag)
\Z end of string (Python/Perl)
^\d+$ entire string must be digits
\bword\b "word" as a whole word, not inside "sword" or "words"
^Error line starts with "Error" (with multiline flag)
Parentheses group sub-expressions and capture their match for later use. Captured groups are numbered left-to-right by their opening parenthesis.
(abc) capturing group โ match available as \1 / $1
(?:abc) non-capturing โ grouping without saving the match
(?<name>abc) named group โ available as \k<name> or ?P<name>
(\w+)\s+\1 # detect repeated word ("the the")
<(\w+)>.*?</\1> # match opening + matching closing HTML tag
(?<q>['"]).*?\k<q> # string in matching quotes
(back-reference must match the same text, not just the same pattern)
cat|dog "cat" or "dog"
(jpg|jpeg|png)$ image file extension at end of string
Lookaround assertions are zero-width โ they check what's around the current position without consuming characters. Useful for adding conditions without including context in the match.
(?=...) positive lookahead โ must be followed by ...
(?!...) negative lookahead โ must NOT be followed by ...
(?<=...) positive lookbehind โ must be preceded by ...
(?<!...) negative lookbehind โ must NOT be preceded by ...
\d+(?= dollars) # number followed by " dollars", match is just the digits
\bfoo(?!bar)\b # "foo" not followed by "bar"
(?<=@)\w+ # word after "@" (e.g. domain in email)
(?<!\d)\d{4}(?!\d) # exactly 4-digit number not adjacent to other digits
Flags change how the pattern is applied. In most languages they
go after the closing delimiter: /pattern/flags.
g global find ALL matches, not just the first
i ignoreCase [a-z] also matches [A-Z]
m multiline ^ and $ match start/end of each line
s dotAll . matches \n too (Python: re.DOTALL)
x verbose allow whitespace + comments in pattern (Python: re.VERBOSE)
// JavaScript
const re = /pattern/gi;
"Hello World".replace(/o/gi, "0"); // "Hell0 W0rld"
# Python
import re
re.findall(r'\d+', text, re.IGNORECASE)
re.sub(r'\s+', ' ', text, flags=re.MULTILINE)
# grep โ use -E for extended regex, -i for case-insensitive
grep -Ei "error|warning" app.log
Any special character can be escaped with \ to
match it literally. The full set of special characters:
. ^ $ * + ? { } [ ] \ | ( )
\. literal dot
\( literal parenthesis
\$ literal dollar sign
https?:// matches "http://" or "https://" (? applies to s only)
\d+\.\d+ decimal number like "3.14"
Raw strings in Python:
Always use r"\d+" instead of "\\d+" โ raw strings prevent Python from consuming the backslash before the regex engine sees it.
Ready-to-use patterns for common tasks. Test and adjust for your specific requirements โ general-purpose patterns always have edge cases.
# Email (simplified โ RFC 5322 is far more complex)
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
# IPv4 address
\b(?:\d{1,3}\.){3}\d{1,3}\b
# Date YYYY-MM-DD
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])
# Hex colour #fff or #ffffff
#(?:[0-9a-fA-F]{3}){1,2}
# URL slug
[a-z0-9]+(?:-[a-z0-9]+)*
# Version number e.g. "v1.2.3"
v?(\d+)\.(\d+)(?:\.(\d+))?
# Key=value pair
(\w+)\s*=\s*(.+)
# Content inside brackets
\[([^\]]+)\] # [like this]
\(([^)]+)\) # (like this)
# Trim leading/trailing whitespace
^\s+|\s+$
# Collapse multiple spaces to one
\s+ โ replace with single space
# Detect duplicate adjacent words
\b(\w+)\s+\1\b
# Remove HTML tags
<[^>]+>
# Match a whole line containing "word"
^.*word.*$