Regular Expression (Regex)
A regular expression (Regex) is a sequence of characters defining a search pattern for text matching, string replacement, and robust input validation.
A Regular Expression (Regex or Regexp) is a formalized sequence of literal characters and metacharacters defining a search pattern used by string-searching algorithms. Regex engines process text to perform data extraction, string parsing, syntax tokenization, and input validation across virtually every major programming language and CLI utility.
Test expressions, capture groups, and replacement strings interactively with our Regex Tester tool or break down complex expressions with the Regex Explainer.
The Essential Developer Regex Cheat Sheet
1. Character Classes & Metacharacters
| Token | Description | Matches | Does NOT Match |
|---|---|---|---|
. |
Any character (except newline, unless s flag enabled) |
a, 9, # |
\n |
\d |
Any digit [0-9] |
0, 5, 9 |
a, -, _ |
\D |
Any non-digit character [^0-9] |
w, !, |
3, 7 |
\w |
Any word character (alphanumeric + underscore) [a-zA-Z0-9_] |
x, Z, 4, _ |
@, -, . |
\W |
Any non-word character | #, , / |
a, 1, _ |
\s |
Any whitespace character (space, tab, newline) | , \t, \r, \n |
a, 0 |
\S |
Any non-whitespace character | A, 8, ! |
, \t |
[abc] |
Character set: matches any single character in brackets | a, b, or c |
d, z |
[^abc] |
Negated set: matches any character not in brackets | d, 1, $ |
a, b, c |
[a-z] |
Range: matches any character within alphabetical range | g, m, z |
A, 9 |
2. Anchors & Word Boundaries
| Token | Description | Functionality |
|---|---|---|
^ |
Start of string (or start of line in multiline mode m) |
Asserts pattern begins at the leading edge. |
$ |
End of string (or end of line in multiline mode m) |
Asserts pattern terminates at trailing edge. |
\b |
Word boundary | Matches position between a word character (\w) and non-word character (\W). |
\B |
Non-word boundary | Matches any position where \b does not match. |
3. Quantifiers: Greedy vs Lazy
Quantifiers control how many times an element must repeat. By default, quantifiers are greedy—they consume as much text as possible. Appending ? makes them lazy (non-greedy), consuming as little text as possible:
| Quantifier (Greedy) | Lazy Variant | Meaning | Match Count |
|---|---|---|---|
* |
*? |
Star | 0 or more times |
+ |
+? |
Plus | 1 or more times |
? |
?? |
Question mark | 0 or 1 time (Optional) |
{n} |
{n}? |
Exact count | Exactly $n$ times |
{n,} |
{n,}? |
Minimum count | At least $n$ times |
{n,m} |
{n,m}? |
Bounded range | Between $n$ and $m$ times |
Lookaround Assertions: Lookahead & Lookbehind
Lookarounds are zero-width assertions: they test whether a condition is true before or after the current position without including matched characters in the final result:
| Syntax | Name | Example | Explanation |
|---|---|---|---|
(?=...) |
Positive Lookahead | \d+(?=px) |
Matches numbers only if directly followed by "px" (e.g. 100 in 100px). |
(?!...) |
Negative Lookahead | \d+(?!px) |
Matches numbers only if not followed by "px" (e.g. 100 in 100em). |
(?<=...) |
Positive Lookbehind | (?<=\$)\d+ |
Matches numbers only if directly preceded by "$" (e.g. 50 in $50). |
(?<!...) |
Negative Lookbehind | (?<!\$)\d+ |
Matches numbers only if not preceded by "$" (e.g. 50 in €50). |
Battle-Tested Production Regex Patterns
1. Simplified RFC 5322 Email Validation
^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$
2. Semantic Versioning (SemVer 2.0.0)
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
3. ISO 8601 UTC Timestamp
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$
ReDoS: The Threat of Catastrophic Backtracking
A Regular Expression Denial of Service (ReDoS) occurs when a regex engine encounters nested or overlapping quantifiers (such as (a+)+$) applied against non-matching input strings.
Because non-deterministic finite automaton (NFA) engines explore every branch of execution, an expression with ambiguous nested paths experiences exponential time complexity ($\mathcal{O}(2^n)$):
Vulnerable Pattern: /^(a+)+$/
Input text: "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!" (28 'a's followed by '!')
Result: > 268,435,456 backtracking steps (CPU frozen at 100%)
How to Prevent ReDoS
- Eliminate Nested Quantifiers: Avoid constructions like
(x+)+,(x*)*, or(a|a+)+. - Use Atomic Groups or Possessive Quantifiers: In engines supporting them (PCRE/Java), use
(?>...)ora++to disable backtracking once a match is found. - Set Execution Timeouts: Always enforce execution timeouts (e.g., 50ms) on user-provided regex inputs.
Code Examples
Modern JavaScript
// Named capture groups and multiline search
const logEntry = "2026-05-08 [ERROR] User 4817 failed login from IP 192.168.1.1";
const regex = /^(?<date>\d{4}-\d{2}-\d{2})\s+\[(?<level>\w+)\]\s+(?<msg>.+)$/;
const match = logEntry.match(regex);
if (match?.groups) {
console.log("Date:", match.groups.date); // "2026-05-08"
console.log("Level:", match.groups.level); // "ERROR"
console.log("Message:", match.groups.msg); // "User 4817 failed login..."
}
Python 3
import re
text = "Contact [email protected] or [email protected]"
pattern = r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+"
emails = re.findall(pattern, text)
print("Found emails:", emails)
Frequently Asked Questions
What is the difference between greedy and lazy matching?
A greedy quantifier matches as much text as possible while allowing the remaining pattern to succeed. A lazy quantifier matches as little text as possible before trying the next token. For example, in the HTML <p>First</p><p>Second</p>, the greedy /<p>.*<\/p>/ matches the whole string from the first <p> to the last </p>, while the lazy /<p>.*?<\/p>/ matches just <p>First</p>.
What are regex flag modifiers (g, i, m, s, u)?
Flags modify how the regex engine evaluates the string:
g(Global): Find all occurrences rather than halting at the first match.i(Case-insensitive): Ignores casing differences (amatchesA).m(Multiline): Makes^and$match the start and end of every individual line (\n).s(DotAll): Allows the dot.metacharacter to match newline characters.u(Unicode): Enables full Unicode code point handling and surrogate pairs.
Why do regex engines behave differently between languages?
Different languages implement different engine architectures. Perl, Python, PHP, and JavaScript historically use NFA (Nondeterministic Finite Automaton) engines supporting rich features like lookaround and backreferences at the cost of potential ReDoS backtracking. In contrast, Google's RE2 and Go use DFA (Deterministic Finite Automaton) algorithms that guarantee linear time ($\mathcal{O}(n)$) execution but forbid lookarounds.
Interactive Tools for Regular Expression (Regex)
Free, browser-based utilities to test, generate, and inspect Regular Expression (Regex) payloads directly.