A developer writes a validation pattern for email addresses, tests it against three examples in the console, ships it, and a week later discovers it rejects addresses with plus tags like user+tag@gmail.com. The pattern was never wrong for the cases tested — it was wrong for the cases not tested. A regex testerthat highlights every match, group, and substitution against real input catches these gaps before they reach production.
Paste a JavaScript-flavour pattern and test string to see live matches, capture groups, and a replace preview with $1-$9 backreferences.
Flags That Change Everything: g, i, m, s, u, y in JavaScript
A pattern behaves completely differently depending on its flags. The g flag finds all matches instead of stopping at the first. Case folds with i. With m (multiline), ^ and $ anchor to line boundaries rather than the string’s start and end, which matters when validating textarea content.
The s flag (dotAll) lets the dot match newlines, which it doesn't by default. The u flag enables \p{L} property escapes and treats surrogate pairs correctly, which is essential for emoji or non-Latin scripts. Sticky mode (y) anchors each match to lastIndex, mostly useful in tokenizers. The MDN regex documentation covers flag interactions in detail.
Capture Groups and Backreferences: Beyond Simple Matching
Parentheses group alternations and capture text for later use.(\\d{4})-(\\d{2})-(\\d{2}) against “2025-06-15” captures year, month, and day as $1, $2, $3. In a replace string you reorder them: $2/$3/$1 turns ISO dates into US format in one pass.
Named groups (?<year>) make the same thing readable six months later. Non-capturing groups (?:) group without storing, which is useful when you need alternation but don't want it polluting your capture list. If $1 shows the wrong text, count opening parentheses left to right. The number matches the group index.
Catastrophic Backtracking: The Regex That Freezes Your Tab
(a+)+b against “aaaaaaaaaaac” doesn't simply fail. It explores an exponential number of ways to split the a’s between the inner and outer quantifiers before giving up. On a long enough input the browser tab hangs. This hits any pattern with nested quantifiers where inner and outer match the same characters.
The fix is restructuring: replace the nested quantifier with a character class that can't overlap, or flatten the group. If your test string takes more than a second to evaluate, the pattern likely has a backtracking trap.
Replace Preview: Testing $1 Substitutions Before They Ship
The replace panel shows output after your substitution runs against the test string. This catches off-by-one group references, unescaped dollar signs, and missing global flags before you commit a codebase-wide find-and-replace that touches 400 files.
Common trip-up: a pattern without the g flag replaces only the first match. The preview shows exactly one substitution and leaves the rest untouched. Easy to miss if your test string has only one occurrence. Always test with at least two matches to confirm global behaviour.
Quick Fixes for Regex Patterns That Almost Work
- Dot not matching newlines. Add the
sflag or replace the dot with[\s\S]for engines that lack dotAll support. - Lookbehind failing in Safari ≤ 15. Safari added lookbehind support late. If you target older WebKit, rewrite as a capture group and filter in code.
- Unicode escapes silently ignored.
\p{L}requires theuflag. Without it the engine treats \p as a literal “p” and matches nothing you expect. - Greedy vs lazy mismatch.
.+grabs everything to the last possible match..+?stops at the first. Swapping greedy for lazy is the single most common regex fix.
Patterns that pass tests but break in prod: anchoring with ^ and $ without the m flag on multiline input, and escaping a backslash in the regex literal but not in the string constructor (new RegExp("\\\\d") needs a double escape).
Related on EverydayBudd's developer utilities hub: the API Rate Limit Planner, where regex patterns commonly come up for validating rate-limit headers and parsing API response payloads.
This tester runs JavaScript (ECMAScript) regex only. Patterns may behave differently in PCRE, Python re, or .NET flavours. Always retest in the target engine before deploying.