Skip to content
← Back

Regex Tester - Online Regular Expression Tester

Network
Runs locally · Not uploaded

Online regex tester with support for g/i/m/s flags. Real-time match highlighting. Runs locally in your browser for fast regex debugging.

Was this result helpful?

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

  1. Plain groups (expr) number by opening-parenthesis order; in a match array, groups start at index 1.
  2. Named groups (?&lt;year&gt;d{4}) bind semantics into replaces: $&lt;year&gt; and $&lt;month&gt; read far better than $1/$2.
  3. Non-capturing groups (?:expr) group without capturing — add ?: whenever you do not need the reference; it saves memory and prevents index shifts.
  4. 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