What the Regex Tester Does

The Regex Tester runs one regular expression against a block of text and prints a match report: every match it found, the character index where each one starts, and the contents of every capture group. It is deliberately a reporting tool rather than a highlighter. You get one line per match in the form [0] "matched text" at index 12, with a second line listing capture groups as a JSON array whenever the pattern contains parentheses.
That distinction matters. A highlighter shows you where matches are; a match report also tells you what your groups actually captured, which is the part developers usually get wrong. A pattern like (\d{4})-(\d{2}) can look correct on screen while the first group silently swallows a different span than you intended. Seeing the group array printed next to the match is the fastest way to catch that.
The tester is useful at two moments: while you are still shaping a pattern and need fast feedback, and after a pattern has already shipped and is misbehaving in production, when you need to run it against the exact input that broke it.

How the Regex Tester Works

Underneath, the tool calls JavaScript's built-in RegExp constructor with your pattern and the flags you toggled, then walks the subject text with matchAll(). Nothing is reimplemented, which is the most important fact about this tool: you are testing the exact engine that will run your pattern in production — V8's Irregexp in Chrome and Edge, SpiderMonkey in Firefox, JavaScriptCore in Safari.
Because it targets ECMAScript, the dialect differs from what you may expect from other ecosystems. This is an ECMAScript pattern, not PCRE, Python or .NET. Lookarounds are supported, named capture groups use (?<name>...), and Unicode property escapes like \p{Letter} require the u flag. Possessive quantifiers and atomic groups do not exist, and neither do \A or \Z. A pattern pasted from a PHP or Python codebase frequently fails here for exactly those reasons — and it will fail in your JavaScript too, which is the point.
One implementation detail is worth knowing before you trust a sticky-flag result. Matching is done through matchAll(), an API that only exists for global regexes, so the tool appends g to your flag set internally. That is why the default flags read g and why results keep coming after the first match even if you toggle g off.
The reported index is a UTF-16 code-unit offset, the same unit String.prototype.indexOf returns. For text outside the Basic Multilingual Plane — emoji, some CJK extensions, mathematical alphanumerics — one visible character occupies two offsets, so an index of 14 may be the eleventh visible glyph.
An invalid pattern does not return a report. The constructor throws and the tool surfaces the engine's own message, prefixed with Invalid regex:. Those messages are precise and worth reading closely — Invalid regular expression: /a{2,1}/: numbers out of order in {} quantifier tells you the engine rejected the pattern before matching ever began.

Using the Regex Tester

  1. Step 1 — Load your subject text. Paste the text you want to search into the main input area. In this tool the textarea holds the subject, not the pattern. Paste the wrong thing into this box and you will see 0 matches no matter how correct your pattern is.
  2. Step 2 — Type the pattern. In the options bar, use the field labelled Pattern (its placeholder is \d+). Enter the pattern body only. Do not wrap it in slashes and do not append flags here; a pasted /\d+/g becomes a literal slash match.
  3. Step 3 — Toggle flags. The Flags row offers six buttons — g, i, m, s, u, y. Active flags render filled. Clicking one adds or removes it, and the set is re-sorted alphabetically after each click, so the toggle order does not matter.
  4. Step 4 — Read the report. Each match produces a line numbered from [0], showing the matched text in quotes and its start index. Patterns with capture groups add an indented groups: line holding the array of captured values.
  5. Step 5 — Read the count. The info line reports the total as N match(es), or 0 matches. Use the copy control to take the whole report into a bug ticket or a code review comment.

Common Use Cases

Shaping a pattern before it ships. Write the expression here, run it against representative input, and confirm the group array contains what you expect before embedding it in a parser, a validator or a router.
Extracting values from pasted output. When a log excerpt, an API response dump or a database export reaches you as a blob of text and you need one field out of every line — request IDs, status codes, timestamps, order numbers — a single pattern with a capture group gives you the full list at once.
Debugging a pattern that regressed. Pin down the smallest input that fails and run it here. Because the report names the index, you can tell immediately whether the failure is about what matched or merely where it matched.
Porting a pattern between languages. Paste the foreign pattern, watch it throw or misbehave, and adjust it to ECMAScript syntax. Reading the engine's rejection message is faster than consulting a flavour-comparison table.
Checking greediness on realistic data. A pattern that behaves on a three-word sample can consume an entire line on a real payload. Testing against the real shape of the data before release catches that class of bug cheaply.

Worked Example

Suppose you are pulling order identifiers out of a queue report. Paste this into the subject textarea:
order 1042 shipped, order 2077 pending
Set Pattern to order (\d+) and leave the default g flag active. The report reads:
[0] "order 1042" at index 0
  groups: ["1042"]
[1] "order 2077" at index 20
  groups: ["2077"]
The count line reports 2 match(es). Both matches include the word order because the whole pattern is the match; only the parenthesised part became group one. If you want the numbers alone, capture the digits and ignore the full match — or change the pattern to \b\d{4}\b, which yields [0] "1042" at index 6 and [1] "2077" at index 26 with no groups at all.
A third variant shows the value of the flags row. Change the pattern to ^order\s+(\d+) with only g active and you get one match, because ^ anchors to the start of the subject. Toggle m as well and the behaviour is unchanged here, since the subject is a single line; the moment your paste contains newlines, m is what lets ^ treat each of them as a separate beginning.

Tips and Common Mistakes

  • In source code, double the backslashes. The pattern field takes a raw pattern, so you type \d here. In a JavaScript string literal the same pattern must be written "\\d", because the string parser consumes one backslash before the regex engine ever sees it. A pattern that works in this tester and fails in your file is almost always this.
  • Overlapping matches do not exist. Matching resumes after the end of the previous match, so the pattern ana finds one match in banana, not two. If you need overlaps you must scan with an explicit advancing index instead.
  • Sticky y is stricter than you may expect. With y active, every match must begin exactly where the previous one ended, so \d+ with gy only matches a run of digits at the very start of the subject.
  • Catastrophic backtracking is a real risk. This is a backtracking engine with no step limit and no timeout. A pattern like (a+)+$ tested against a long non-matching string can lock the tab. Prefer explicit alternatives and possessive-style rewrites such as (?:a+)+ avoidance, and test with the largest realistic input.
  • The s flag changes what a dot means. Without it, . will not cross a newline. A multiline pattern that quietly returns no matches is very often missing either s or m.
  • The u flag makes the engine stricter, not just smarter. It enables code-point semantics — surrogate pairs behave as one character — and simultaneously turns some previously tolerated escapes into syntax errors.

Frequently Asked Questions

Which regex flavour does this tester use?

ECMAScript, via the browser's own RegExp engine. That is deliberate: it is the same engine your shipped JavaScript will use. Lookarounds and named groups work in current Chrome, Firefox and Safari. Possessive quantifiers, atomic groups (?>...) and Python's (?P<name>...) group syntax will not, and neither will \A or \Z.

Why does my pattern fail here but work in another tool?

The other tool probably uses a different dialect. Most online regex testers offer a flavour selector and quietly default to something PCRE-like. If a pattern relies on a Perl-only construct it will pass there and throw here — and throw in your production JavaScript as well.

Why does ^ not match the second line of my input?

Because the m flag is off. Without it, ^ and $ treat the whole subject as a single string and anchor only at its absolute beginning and end.

Can I paste a JavaScript literal like /\d+/gi?

No. Split it first: the pattern body \d+ goes in the Pattern field and the modifiers go in the Flags row. Tester fields take the bare pattern, without delimiters.

Does the tester show named capture groups by name?

It prints capture groups positionally, as a JSON array, so a named group appears as its value in array order rather than under its name. Use the array position to identify it, or test the pattern with the Regex Explainer if you need the structure spelled out.

Why do I see zero matches for a pattern I am certain is correct?

Three causes cover almost every case: the subject text was pasted into the Pattern field by mistake, the flags are missing m or s, or the pattern was copied with its slashes and flags still attached.

Related Tools

Once a pattern matches correctly here, the Regex Replace Tester shows what it would transform using the same engine and the same flag toggles. If you need the pattern's components spelled out rather than its results, the Regex Explainer lists the token types it recognises. To build an initial pattern from sample lines, start with the Regex Generator and verify the result back here. For ready-made starting points covering email addresses, URLs, IPv4 addresses, phone numbers, hex colours and ISO dates, the Regex Cheatsheet Search returns a recipe you can paste straight into the Pattern field.

Privacy & Security

This tool runs entirely in your browser — no data ever leaves your device. There is no server round-trip, no upload, no logging, and no account required. Your input is processed locally using client-side JavaScript and is never stored, transmitted, or accessible to anyone else. When you close the tab, everything disappears.