JavaScript Regex Tester: Flags & Groups
Use a JavaScript regex tester to inspect flags, capture groups, replacements, Unicode behavior, and ReDoS risks before code reaches production safely.
Control Plane Labs Staff
Published September 15, 2026
The Regex tester on Control Plane Labs uses the browser’s ECMAScript engine. It shows matches, capture groups, and replacement output instead of reducing a pattern to a green “matched” label.
What a JavaScript regex actually matches
JavaScript regular expressions describe a pattern over a string. You can create
one as a literal, such as /error:\s+\d+/, or with the RegExp constructor
when the pattern arrives as a string. The ECMAScript specification’s RegExp
section
defines the object, its flags, and the matching algorithms. MDN’s regular
expression reference
is a useful index for the syntax details.
The smallest useful test has three parts:
const pattern = /service=(?<name>[a-z-]+); status=(?<code>\d+)/;
const input = "service=api-gateway; status=502";
const match = pattern.exec(input);
console.log(match.groups.name); // "api-gateway"
console.log(match.groups.code); // "502"
The parentheses create capture groups. A named group gives later code a stable
label; numbered groups are still available in the match array. A regex does not
know that 502 is an HTTP status or that api-gateway is a service name. It
only applies the pattern you wrote, so make the test string resemble the real
log, header, URL, or configuration value.
Which flags should you test?
Flags change the meaning of anchors, dots, character interpretation, and iteration. Test the flags you will deploy rather than adding a familiar set by habit.
gfinds successive matches. It also makes methods such asexec()andtest()stateful throughlastIndex; MDN’stest()reference documents the boolean result and this state interaction.iignores case for the pattern’s case-sensitive comparisons.mmakes^and$work at line boundaries as well as the beginning and end of the whole input. Without it, a multi-line log is still one string.slets.match a line terminator. It does not make a character class or a quantifier safer; it only changes the dot.uenables Unicode-aware pattern behavior. The specification distinguishes a Unicode pattern from a BMP pattern, which matters for code points represented by surrogate pairs.yis sticky: a match must begin at the currentlastIndexrather than searching forward. It is useful for tokenizers, but surprising when a pattern is expected to scan freely.
The specification also defines newer d and v modes. Check runtime support
before shipping them, and show exact flags so another reader can reproduce the
result.
Why exec() sometimes appears to skip a match
exec() returns a match array or null; with g or y, the RegExp object
updates lastIndex between calls. The ECMAScript algorithm for
exec()
defines that behavior. This code therefore advances through the input:
const re = /cat/g;
const text = "cat scat";
console.log(re.exec(text)[0]); // "cat"
console.log(re.exec(text)[0]); // "cat"
console.log(re.lastIndex); // 8
The second match begins inside scat, not at the start of the word. For
independent boolean checks, reset lastIndex or omit g. Inspect match indexes
and matched text when a zero-length pattern is involved.
Captures, replacement tokens, and Unicode
Capturing is different from matching. In /(user):(\d+)/, the whole match is
user:42, group 1 is user, and group 2 is 42. A non-capturing group
(?:...) groups alternatives without changing the numbered captures that
follow it. Named groups make complex patterns easier to review, but names must
remain unique within a pattern.
Replacement strings have their own mini-language. "$&" means the whole match,
"$1" means the first numbered group, "$<name>" means a named group, and
"$$" inserts a literal dollar sign. The MDN replace() reference
lists these tokens and the callback form. Put a deliberately awkward sample in
the replacement pane: a missing group, a dollar sign, and two matches will
expose most mistakes.
Unicode is another reason to test real text. Without u, a non-BMP character
can be represented as two UTF-16 code units; with u, the pattern uses Unicode
code-point semantics. A grapheme can still contain combining marks or emoji
sequences, so regex may not represent one displayed character.
JavaScript regex versus RE2 and other engines
Regex syntax is not portable by default. JavaScript supports backreferences,
lookarounds, named groups, and its own flag set. RE2 intentionally accepts a
different subset; its syntax reference
lists constructs that are not supported. Go’s standard
regexp package is RE2-based, so a pattern tested
in JavaScript may need a rewrite before it can run in a Go service. The Rust
regex crate documents another
deliberately limited dialect.
Write down the target engine beside the pattern. A lookbehind that succeeds in Node.js is not evidence that a RE2-backed service will accept it. Test the production dialect, not only the editor where the pattern was composed.
How to avoid ReDoS while testing
Backtracking engines can spend a very long time exploring alternatives in
patterns with nested or overlapping quantifiers. OWASP describes this
regular-expression denial-of-service risk
as a case where crafted input causes excessive matching work. A pattern such as
(a+)+$ against a long run of a characters followed by a non-matching
character is a classic warning shape.
The safe workflow is practical:
- Keep test strings short while you are editing a pattern. Add length deliberately when you are checking performance.
- Treat a pattern supplied by another user as untrusted code. Do not run it in the main thread of a service that must stay responsive.
- Prefer a linear-time engine such as RE2 when you do not need backreferences or lookaround. The engine choice is a safety boundary, not just a syntax preference.
- Cap input size, match count, and execution time in any server-side wrapper. A JavaScript timeout cannot interrupt a synchronous regex call already running on the same event loop, so isolation is stronger than a stopwatch.
- Keep the tester’s warning enabled. A heuristic can reject a safe pattern or miss a risky one; it is a review aid, not a proof of safety.
The browser tool caps sample and match work and asks for an explicit override on patterns that resemble catastrophic backtracking. That is an exploration aid, not permission to place a pattern in production without an engine and resource policy.
A compact review checklist
Before committing a regex, test a normal value, a boundary value, malformed input, and a longer value. Record the engine and flags, inspect every group, and run the replacement preview with a literal dollar sign. For structured data, use the JSON formatter or a real parser instead of extending one pattern until it becomes a grammar.
The HTTP header inspector is a useful companion when a pattern is meant to inspect a response, while the URL encoder/decoder helps separate encoded delimiters from the text the regex should actually match.
Frequently asked questions
What is the difference between a regex tester and a regex validator?+
Why does JavaScript regex test return true and then false?+
g or y flag carries state in lastIndex. Reset that property before an independent check, or omit the stateful flag when you only need a boolean test.Should I use a regex to parse JSON or HTML?+
What makes a regex vulnerable to ReDoS?+
Why does a regex work in JavaScript but not in Go?+
Read next
- Try the Regex tester.
- Read Regex patterns you will actually use.
- Inspect response fields with the HTTP header inspector.
Tags: #regex, #javascript, #regular-expressions, #web-development, #security