Regex Tester

Build, test, and debug regular expressions with live match highlighting, capture group display, and a full cheatsheet. 100% client-side.

/ /
Enter a pattern above to start matching.
Character classes
Quantifiers
Anchors & groups
Match Preview
Enter a regex pattern to see highlighted matches here.

How Regular Expressions Work

A regular expression (regex) is a sequence of characters that defines a search pattern. The JavaScript regex engine processes patterns using a state machine — it advances through the input string character by character, attempting to match the pattern at each position. When it finds a match, it records the position and (if using the global flag) continues searching from the end of that match.

Modern JavaScript regexes support the full ECMAScript specification including named capture groups ((?<name>...)), Unicode property escapes (\p{Letter} with the u flag), lookbehind assertions, and the d flag for match indices. All matching in this tool runs in your browser using the built-in JavaScript RegExp engine.

Regex Flags Explained

Capture Groups vs Non-Capturing Groups

A capturing group (abc) records the matched substring and makes it available as a numbered back-reference ($1, $2) or in the match array. Use capturing groups when you need to extract specific parts of a match.

A non-capturing group (?:abc) groups part of a pattern without creating a reference. This is more efficient when you only need the grouping behavior for quantifiers or alternation, not the captured value.

// Capturing — $1 = area code
const phone = '(415) 555-1234'.match(/\((\d{3})\)\s(\d{3}-\d{4})/);
// phone[1] = '415', phone[2] = '555-1234'

// Non-capturing — just grouping for the quantifier
const date = '2026-05-28'.match(/(?:\d{4})-(\d{2})-(\d{2})/);
// date[1] = '05', date[2] = '28' (year not captured)

Lookahead and Lookbehind

Lookaround assertions match positions in the string without consuming characters. They are zero-width — they test that a condition is (or is not) true at the current position, then let the rest of the pattern match from that same position.

// Positive lookahead: match word only if followed by a digit
/\w+(?=\d)/.exec('foo3 bar baz2')  // 'foo', 'baz'

// Negative lookahead: match word NOT followed by a digit
/\w+(?!\d)\b/.exec('foo3 bar')     // 'bar'

// Positive lookbehind: match digits preceded by '$'
/(?<=\$)\d+/.exec('price $42')    // '42'

Catastrophic Backtracking

Catastrophic backtracking occurs when a regex with nested quantifiers and ambiguous patterns is applied to a string that almost-but-not-quite matches. The engine explores an exponential number of combinations. The classic example is (a+)+ on the string "aaaaaab" — the engine tries every possible grouping before concluding no match.

To avoid it: use possessive quantifiers or atomic groups where available, prefer specific character classes over .*, and test patterns on long near-miss strings before deploying to production. Regular expression denial-of-service (ReDoS) is a real security vulnerability that has affected Node.js applications and web servers.

Frequently Asked Questions

What is the difference between greedy and lazy quantifiers?

Greedy quantifiers (*, +, {n,m}) match as many characters as possible while still allowing the overall pattern to match. Lazy (non-greedy) quantifiers (*?, +?, {n,m}?) match as few characters as possible. For example, given the string "<b>bold</b>", the pattern <.+> greedily matches the entire string, while <.+?> lazily matches just <b> and then </b> separately.

How do I match a literal dot, star, or other special character?

Escape special regex characters with a backslash. The special characters are: . * + ? ^ $ { } [ ] | ( ) \. To match a literal dot use \., a literal asterisk use \*, a literal backslash use \\, and so on. When building regex patterns from user input programmatically, use a helper function to escape all special characters before constructing the pattern.

Why does my regex match differently with and without the global flag?

Without the global flag, String.match() returns the first match plus its capture groups in a single array. With the global flag, it returns an array of all full-match strings but does not include capture group details. To iterate over all matches with their capture groups, use String.matchAll() (returns an iterator), or call RegExp.exec() in a loop. Also note that stateful regex objects with the global flag remember lastIndex — calling exec() repeatedly on the same regex object advances through the string.

How do I match across multiple lines?

Use the s (dotAll) flag to make . match newline characters. Use the m (multiline) flag to make ^ and $ match at the start and end of each line rather than the entire string. For matching an entire block across lines, a common pattern is [\s\S]+? or (?:.|\n)+? which explicitly includes whitespace and non-whitespace characters.

What are named capture groups and when should I use them?

Named capture groups (?<name>pattern) let you reference matched substrings by name instead of position number. They are available in JavaScript since ES2018. Use them when you have multiple groups and index-based references would be fragile — especially if the order of groups might change. In replacement strings, use $<name>. In the match object, access them via match.groups.name. Named groups make regex patterns self-documenting.

Related Tools

Built by Michael Lip. 100% client-side. No data leaves your browser.