Online regex tester with support for g/i/m/s flags. Real-time match highlighting. Runs locally in your browser for fast regex debugging.
TL;DR: Free online regex tester with support for g/i/m/s flags. Real-time match highlighting for fast debugging. Runs entirely locally in your browser, no registration required.
For local tools, open DevTools → Network and search your input — it should not appear in requests.
Next steps
Usage Guide
Test regular expressions live in your browser: enter a pattern and sample text, matches highlight instantly, and capture groups, named groups and the global/multiline/case-insensitive flags render visually. Engine: JavaScript RegExp only (not PCRE, Python, Go, or .NET). Dialect differences routinely cause works-locally-fails-in-production — this tool executes browser JavaScript semantics and calls out the cross-language divergence points.
1. The five flags and their traps
- Honesty first: this page is JavaScript RegExp in the browser — not regex101 PCRE mode. Patterns with recursion, (?(cond)), or \K will not work here even if they work elsewhere.
- g (global): the basis of matchAll and replace; but RegExp.prototype.test with g advances lastIndex — the classic reason repeated test calls on the same regex object alternate between true and false.
- i (case-insensitive): for non-ASCII text, pair it with the u flag for stable behavior.
- m (multiline): only affects ^ and $ anchoring; it does not make the dot match newlines (that needs s or [sS]).
- s (dotAll): lets . match newlines — available since ES2018; in older environments substitute [sS].
- u (Unicode): prerequisite for \p{...} property escapes; keep it on when handling CJK or emoji. Named groups (?<name>...) and lookbehind are supported in modern browsers; confirm your target runtime before shipping.
2. Greed, laziness and catastrophic backtracking
Quantifiers are greedy by default: a.*b against a x b x b runs to the end of the line before backtracking, matching the longest a...b. Adding a question mark (.*?) switches to lazy, matching the shortest hit. Most regex performance disasters come from catastrophic backtracking: nested quantifiers like (a+)+b on an almost-matching input explode the combination count exponentially and freeze the tab. Defenses: bound your quantifiers ([^<>]+ over .+), use atomic groups where the engine supports them (or restructure, since JavaScript lacks possessive quantifiers), and always pre-check length and character class on untrusted input.
3. Why capture groups and named groups matter
- Plain groups (expr) number by opening-parenthesis order; in a match array, groups start at index 1.
- Named groups (?<year>d{4}) bind semantics into replaces: $<year> and $<month> read far better than $1/$2.
- Non-capturing groups (?:expr) group without capturing — add ?: whenever you do not need the reference; it saves memory and prevents index shifts.
- Enable named-group display in this tool and verify each group actual captured content — the fastest way to debug a regex that does not grab.
4. Cross-engine dialect notes
The same pattern behaves differently across engines: JavaScript lacks recursion and K; Java requires doubled backslashes in string literals (\d); Python re lacks atomic groups unless you pull in the third-party regex package; PCRE and Go (RE2) run linear time but forbid backreferences. Before shipping a JavaScript-verified regex to a backend language, walk this divergence list — it preempts a whole class of works-on-my-machine bugs.
5. Everyday regex snippets
- Numbers: integer ^-?d+$; two decimal places ^-?d+.d{1,2}$; thousands separators via replace(/B(?=(d{3})+(?!d))/g, ',').
- CJK range: [一-龥] covers the basic block; full-width punctuation needs separate handling.
- URL extraction: https?://[^s)>]]+ is a good coarse match; for strict validation use the URL constructor, not regex.
- Password triple check: /(?=.*[a-z])(?=.*[A-Z])(?=.*d).{8,}/ — assert first, consume after.
- Trim: replace(/^s+|s+$/g, '') — semantically equivalent to trim and works in old runtimes.
6. How to test a regex properly
Prepare at least four case classes: standard positive samples; boundary positives (empty string, single character, maximum length); near-miss negatives (one extra symbol, full-width versus half-width); and adversarial strings that trigger catastrophic backtracking. Freeze these into unit tests and run them on every regex change — regexes are the classic fast-to-write, scary-to-modify construct, and the test set is the only peace of mind.
FAQ
This page runs your browser's JavaScript RegExp only — not PCRE, Python re, Go RE2, or .NET — and a badge at the top states “JavaScript RegExp only”. JavaScript lacks recursion and conditionals, has no \K, and no possessive quantifiers yet: the most common gaps when porting across dialects.
g, i, m, s, u, and y, freely combinable. Three gotchas: m only changes how ^ and $ anchor to lines — making the dot cross newlines takes s or [\s\S]; \p{...} property escapes require u, which is worth keeping on for Chinese and emoji; and calling test() repeatedly on the same regex object with g advances lastIndex, which is exactly why consecutive tests flip between true and false.
Most likely catastrophic backtracking: nested quantifiers like (a+)+b explode combinatorially on input that almost matches. Defenses: use bounded classes such as [^<>]+ instead of .+, and pre-check length for untrusted input. JavaScript has no possessive quantifiers yet, so restructure the pattern when needed — and stress-test adversarial samples here before shipping.
A named group like (?<year>\d{4}) is referenced as $<year> in replace — far more readable than $1/$2 — and modern browsers also support variable-length lookbehind ((?<=...) / (?<!...)). Write groups you never reference as non-capturing (?:expr) to save memory and keep numbering aligned. Turn on named-group display to inspect what each group actually captured; it is the fastest way to debug a pattern that keeps missing matches.
The same pattern behaves differently across engines: Java string literals require doubled backslashes (\d becomes \\d); Python's built-in re lacks atomic groups — the third-party regex library adds them; PCRE and Go (RE2) run in linear time but ban backreferences. Run through this checklist before shipping and you will avoid a batch of “worked on my machine” bugs.
All processing happens in your local browser: matching, highlighting, and capture-group parsing make no network requests, and your text and patterns are never sent to any server.
Related Tools
Related Articles
Regex Not Matching? Troubleshoot These 6 Common Pitfalls
How to troubleshoot when a regex doesn't match or matching fails? This article walks through 6 common pitfalls — greedy quantifiers, missing flags, unescaped special chars, lookaround assertions, newline handling, and Unicode properties — with before/after examples to help you quickly locate regex debugging issues.
Regex Matches Nothing / Greedy .* Swallows Results — How to Fix
Online regex test matches nothing, or greedy .* eats too much, or groups capture nothing? Explains greedy vs lazy, escaping special chars, and anchors — with a step-by-step debug using our regex tester.
Online Regex Explainer: Visualize and Understand Regular Expressions
Learn how to parse and understand regular expressions — lazy quantifiers, lookarounds, named groups, Unicode properties, and how to pair an explainer with a tester.