What Is a Regular Expression?
A regular expression (regex or regexp) is a sequence of characters that defines a search pattern. It is a mini-language embedded in almost every programming language for searching, extracting, and replacing text.
The pattern /^\d{3}-\d{4}$/ matches a US local phone number format: exactly three digits, a hyphen, and four digits, with nothing before or after.
Core Syntax
Character classes.
.— any character except newline\d— digit (0–9);\D— non-digit\w— word character (letter, digit, or underscore);\W— non-word\s— whitespace;\S— non-whitespace[abc]— any of a, b, or c[^abc]— any character except a, b, or c[a-z]— any lowercase letter
Quantifiers.
*— 0 or more+— 1 or more?— 0 or 1 (optional){n}— exactly n times{n,m}— between n and m times{n,}— n or more times
Anchors.
^— start of string (or start of line in multiline mode)$— end of string (or end of line in multiline mode)\b— word boundary\B— non-word boundary
Groups and alternation.
(abc)— capturing group(?:abc)— non-capturing groupa|b— alternation (a or b)(?=abc)— positive lookahead(?!abc)— negative lookahead
Flags.
g— global (find all matches, not just first)i— case-insensitivem— multiline (^and$match line boundaries)s— dotAll (.matches newlines)
Common Patterns
# Email (simplified)
^[^\s@]+@[^\s@]+\.[^\s@]+$
# URL
https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b
# Date YYYY-MM-DD
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
# Hex color
^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
# IPv4 (simplified)
^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$
# UUID v4
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
Catastrophic Backtracking
The most dangerous regex bug is catastrophic backtracking. Certain patterns with nested quantifiers (like (a+)+) cause exponential backtracking on specific inputs, making the regex engine hang for seconds or minutes.
Example: /^(\w+\s?)*$/ against the input "aaaaaaaaaaaaaaaaaaaaaaaa!" causes catastrophic backtracking in most engines because the engine exhaustively tries every way to partition the string.
The fix: redesign the pattern to avoid ambiguity, use atomic groups (if supported), or add possessive quantifiers.
Greedy vs. Lazy Matching
Quantifiers are greedy by default — they match as much as possible.
"<b>text</b> more <b>bold</b>".match(/<b>.*<\/b>/g)
// Returns: ['<b>text</b> more <b>bold</b>'] — matches too much!
"<b>text</b> more <b>bold</b>".match(/<b>.*?<\/b>/g)
// Returns: ['<b>text</b>', '<b>bold</b>'] — lazy, matches minimum
Add ? after a quantifier to make it lazy: .*?, +?, {n,m}?.
Try It
The Regex Tester on Syntaxly lets you write a pattern, set flags, and test it against sample text in real time, with match highlighting.