Skip to content

Regex Tester

Test JavaScript regular expressions against sample text with live match highlighting, named capture groups and a replace preview — all six flags explained.

Pattern

//gm

Test string

3 matches
Highlighted
Contact ada@example.com or grace.hopper+navy@navy.mil.
Invalid: not-an-email@, @nodomain.com
Support: support@dev-toolkit.io

Replace

$1, $<name> and $& are supported

Matches

Match 1index 8
ada@example.com
$1ada
$2example.com
userada
domainexample.com
Match 2index 27
grace.hopper+navy@navy.mil.
$1grace.hopper+navy
$2navy.mil.
usergrace.hopper+navy
domainnavy.mil.
Match 3index 102
support@dev-toolkit.io
$1support
$2dev-toolkit.io
usersupport
domaindev-toolkit.io

About the Regex Tester

Regular expressions are hard to read and easy to get subtly wrong, so the fastest way to write one is to watch it match. This tester compiles your pattern with the JavaScript engine as you type, highlights every match inside the test string, and lists the capture groups for each one — including named groups.

It uses the browser's own RegExp implementation, which means the results are exactly what your JavaScript or TypeScript code will produce. Patterns written for PCRE, Python's re module or Go's RE2 mostly transfer, but the differences that bite — lookbehind support, named group syntax, and the absence of recursive patterns — show up here immediately rather than in production.

Every one of the six JavaScript regex flags is exposed with an explanation, not just g and i. The m flag changes what ^ and $ anchor to; s makes . match newlines, which it otherwise never does; u switches on Unicode-aware mode, changing how the pattern reads code points beyond the Basic Multilingual Plane; y anchors matching to lastIndex exactly, which is what a hand-rolled tokenizer needs and what g alone cannot give you. Getting a flag wrong produces a pattern that looks right on a simple test string and fails on the input that actually matters.

  • Live match highlighting with every match numbered
  • Numbered and named capture groups listed per match, including ones that matched nothing
  • All six JavaScript flags toggleable, each with an explanation
  • Replace preview supporting $1, $<name> and $& substitution
  • Copy the pattern as a ready-to-paste /pattern/flags literal

How to use it

  1. Type your pattern into the field between the slashes — no need to escape forward slashes.
  2. Toggle flags underneath. g finds every match instead of just the first; i ignores case; m makes ^ and $ match at line breaks.
  3. Paste the text you want to match into the test string pane. Matches highlight as you type.
  4. Read the Matches panel on the right for capture groups and the index of each match.
  5. Open Replace to preview a substitution before running it in your editor.

Real-world use cases

Frontend & backend developers

Work out the exact pattern for a form-input validator or a URL router directly against real sample input, instead of iterating by editing code and reloading the page.

QA & test engineers

Verify a regex used in a test assertion actually matches every valid case and rejects every invalid one you can think of, before it ships inside a test helper nobody reads closely again.

DevOps & log analysis

Build and check a log-parsing pattern against real log lines pasted straight from a terminal, catching a greedy quantifier that would have swallowed the wrong field in production.

Data engineers

Prototype an extraction pattern for a data-cleaning pipeline against a sample of the messy real data, before running it across a full dataset where a mistake is expensive to rerun.

Security engineers

Check whether an input-validation regex is vulnerable to catastrophic backtracking by testing it against adversarial input, before it becomes a ReDoS finding in someone else's audit.

Examples

Named capture groups

Input
/(?<user>[\w.+-]+)@(?<domain>[\w-]+\.[\w.]+)/g

ada@example.com
Output
Match 1  ada@example.com
user     ada
domain   example.com

Named groups are far more maintainable than $1 and $2 — and in a replacement string you refer to them as $<user>.

Why m changes everything

Input
/^error/gm

ok
error: disk full
Output
Without m: no match
With m:    error (line 2)

Without the m flag, ^ anchors to the start of the whole string, not the start of each line.

Greedy versus lazy

Input
/<.+>/  vs  /<.+?>/

<a><b>
Output
greedy  <a><b>
lazy    <a>

Adding ? after a quantifier makes it match as little as possible. This one difference accounts for a large share of regex bugs.

Common errors

MessageCauseFix
Invalid regular expression: Unterminated groupAn unbalanced ( — often a literal parenthesis that was not escaped.Escape literal parentheses as \( and \), or balance the group.
Invalid regular expression: Nothing to repeatA quantifier (*, +, ?) with no preceding token, such as a pattern starting with *.Put a character, class or group before the quantifier, or escape it as \*.
Invalid escape / Invalid groupA pattern copied from another flavour — \A, \Z, (?P<name>...) and possessive quantifiers do not exist in JavaScript.Use ^ and $ for anchors and (?<name>...) for named groups.
Matches only the first occurrenceThe g flag is missing, so replace() and match() stop after one hit.Add g. Note that a global regex also carries lastIndex state if you reuse the object across calls.
The page freezes on a long inputCatastrophic backtracking — nested quantifiers such as (a+)+b explode exponentially on a non-matching string.Avoid nesting quantifiers over overlapping character sets, anchor the pattern, and prefer specific classes over .*.

Frequently asked questions

Which regex flavour does this use?

The JavaScript (ECMAScript) engine built into your browser, so results match what your JS or TypeScript code will do. Lookbehind, named groups and Unicode property escapes are supported in current browsers; recursive patterns and possessive quantifiers do not exist in JavaScript at all.

Why does my pattern from Python or PHP not work?

The syntax families differ in specific places. Python's (?P<name>...) is (?<name>...) in JavaScript, \A and \z become ^ and $, and inline modifiers like (?i) are not supported — use the i flag instead.

What is the difference between the g and y flags?

g finds matches anywhere after the previous one. y (sticky) requires the match to start exactly at lastIndex, which is useful for writing tokenisers where gaps are errors.

Why does my capture group show as undefined?

The group is inside an alternation or an optional section that did not participate in the match. That is normal — always guard against undefined when reading match[n] in code.

Can a regular expression hang my browser?

Yes. Patterns with nested quantifiers can backtrack exponentially, which is the basis of ReDoS attacks. This tester caps the match list at 2000 to keep rendering responsive, but a pathological pattern can still block the tab — the same way it would block your server. That is a reason to fix the pattern, not to work around it.

Is my test data sent anywhere?

No. The pattern and the test string stay in your browser; matching runs locally with the built-in RegExp engine.

What is the difference between the u and y flags and when do I need them?

u switches the pattern into Unicode-aware mode, changing how code points outside the Basic Multilingual Plane — many emoji, some CJK extension characters — are read; without it, a surrogate pair can be split and matched incorrectly. y (sticky) requires a match to start at exactly lastIndex rather than anywhere after it, which is the flag a hand-rolled tokenizer needs so that a gap between tokens is treated as an error instead of being silently skipped.

Why does replace() only replace the first match without the g flag?

Because that is the documented default behaviour of String.prototype.replace() with a RegExp argument — without g it stops after one substitution, regardless of how many times the pattern could match. This trips people up because replaceAll() has no such gotcha; with a regex argument, replaceAll() actually throws if the g flag is missing, specifically to catch this mistake early.

Last updated