Skip to content
Control Plane Labs

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.

  • g finds successive matches. It also makes methods such as exec() and test() stateful through lastIndex; MDN’s test() reference documents the boolean result and this state interaction.
  • i ignores case for the pattern’s case-sensitive comparisons.
  • m makes ^ 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.
  • s lets . match a line terminator. It does not make a character class or a quantifier safer; it only changes the dot.
  • u enables Unicode-aware pattern behavior. The specification distinguishes a Unicode pattern from a BMP pattern, which matters for code points represented by surrogate pairs.
  • y is sticky: a match must begin at the current lastIndex rather 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:

  1. Keep test strings short while you are editing a pattern. Add length deliberately when you are checking performance.
  2. 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.
  3. 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.
  4. 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.
  5. 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?+
A tester shows matches, groups, flags, and replacement output. A validator checks whether a whole value conforms to a rule; it normally needs anchors and an explicit empty-input policy.
Why does JavaScript regex test return true and then false?+
A regular expression with the 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?+
No. Use a JSON or HTML parser for the document, then use a regex for a small, well-defined token if needed.
What makes a regex vulnerable to ReDoS?+
Nested or overlapping quantifiers can make a backtracking engine explore many possible paths for a non-matching input. Keep patterns simple, cap input, isolate untrusted work, or choose a linear-time engine such as RE2.
Why does a regex work in JavaScript but not in Go?+
The languages use different regex dialects. Go's standard regexp package follows RE2-style syntax and omits constructs such as backreferences and lookaround that JavaScript supports.

Tags: #regex, #javascript, #regular-expressions, #web-development, #security