Regex tester

Test a JavaScript regex live: matches, capture groups and a replace preview.

JavaScript (ECMAScript) syntax, written without the slashes.

Flags

Use $1, $<name>, $& for the whole match and $$ for a dollar sign.

Matches

Type a pattern to see the matches.

What this tool does

A regular expression, or regex, is a short pattern that describes a set of strings: "four digits, a dash, two digits" or "anything between angle brackets". This tool tests a pattern against your own text while you type. It highlights every match, lists each match with its position, shows what every capture group caught, and previews the result of a replacement such as $2, $1. Nothing you paste is uploaded: the search runs in your browser.

It uses the regular expression engine of your browser, which means the JavaScript (ECMAScript) flavour. That is the right choice when the pattern will run in JavaScript, TypeScript, Node.js or a browser. Other languages differ in details: Python and PCRE accept some syntax that JavaScript does not, such as possessive quantifiers and (?i) inline flags, while named groups are written (?<name>...) in JavaScript, .NET, Java and PHP but (?P<name>...) in Python.

How to test a pattern

  1. Type the pattern in the first box, without the surrounding slashes. \d{4}-\d{2} is the pattern; /\d{4}-\d{2}/g is how it looks in source code.
  2. Switch the flags you need. g is on by default so that every match is found, not only the first.
  3. Paste or type your test text. Matches are highlighted in two alternating colours, so two neighbouring matches stay distinguishable.
  4. Read the table under the highlighted text: each match with its start and end position, and one row per capture group. A group that did not take part in the match says so, which is different from a group that matched an empty string.
  5. To rewrite the text, fill in "Replace with". It follows the rules of String.prototype.replace: $1 to $99 are numbered groups, $<name> is a named group, $& is the whole match and $$ is a literal dollar sign.

Flags explained

FlagNameWhat it changes
gglobalFinds every match instead of stopping at the first
iignore casecat also matches Cat and CAT
mmultiline^ and $ match at every line break, not only at the ends of the text
sdot matches newline. also matches a line break
uunicodeReads the text as code points: an emoji counts as one character and \p{L} property escapes work
vunicode setsA stricter successor of u with set operations such as [\p{L}--[a-z]]; browsers without it show the chip disabled
ystickyMatches only exactly where the search starts

Positions are counted in UTF-16 code units, which is how JavaScript's own index works, so an emoji without the u flag takes two positions. The d flag (match indices) is switched on behind the scenes to read the position of each group.

A worked example

Take the text 2026-10-13 and the pattern (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}). There is one match at position 0 with length 10 and three groups: year 2026, month 10 and day 13. With "Replace with" set to $<day>/$<month>/$<year> the preview shows 13/10/2026.

Greedy against lazy: on <b>bold</b> and <i>italic</i> the pattern <.+> finds one match, the whole string, because .+ takes as much as it can. The pattern <.+?> finds four: <b>, </b>, <i> and </i>. The question mark makes the repeat lazy.

Empty matches: x* can match nothing, so on ab with the g flag it matches three empty strings, at positions 0, 1 and 2. The tool marks each with a thin bar, steps over them without looping, and a replacement of - gives -a-b-.

Why a pattern can hang

Some patterns take exponentially longer with every extra character. This is called catastrophic backtracking. The classic case is ^(a+)+$ tested against a long run of the letter a followed by b: the engine tries every way of splitting the a characters between the inner and the outer repeat before it gives up. On one test machine 26 a characters followed by b took about a second and a half, and each extra character roughly doubles that. In a web service this is a real denial-of-service risk, known as ReDoS.

This page runs the search in a background worker and stops it after 2 seconds, so the tab stays responsive and you get a message instead of a frozen page. You can also press Stop. The fix is usually to remove the nested repeat: ^a+$ gives the same answer in microseconds. Where you cannot, avoid overlapping alternatives such as (a|a)* and limit repeats with a bound like {1,20}.

Common mistakes

  • Forgetting to escape. . matches any character, so write \. for a literal dot. The same goes for parentheses, brackets, braces, +, ?, ^, $, | and the backslash itself.
  • Expecting `^` and `$` to work per line without the m flag.
  • Forgetting `g` when replacing, so only the first match changes.
  • Trying to parse HTML or every valid e-mail address with a regex. A pattern is fine for finding candidates; nested tags and the full e-mail grammar need a real parser.
  • Pasting a pattern together with its slashes and flags, such as /ab+c/gi. Type only the part between the slashes and use the flag chips.

To see what a replacement changed line by line, paste both versions into the diff checker. For quick clean-ups that need no pattern at all, the text toolkit covers case, spaces and accents. If you want to schedule a job instead of matching text, the cron explainer reads a schedule in plain words.

Frequently asked questions

Which regex flavour does this tester use?

The JavaScript (ECMAScript) flavour of your own browser. It is the right one for JavaScript, TypeScript and Node.js. For Python, PHP, Java or .NET most everyday patterns work unchanged, but check features such as inline flags, possessive quantifiers and atomic groups in that language's documentation.

Is my text uploaded anywhere?

No. The pattern and the text stay in your browser and are processed by a background worker on your device. Nothing is sent over the network.

Why was my pattern stopped after 2 seconds?

It probably backtracks catastrophically: nested repeats such as (a+)+ on a long text make the engine try an exponential number of paths. The tool stops the run so the page stays usable. Simplify the pattern, remove the nested repeat or limit it with a bound.

Why are the positions different from my editor?

Positions here are JavaScript string indexes, counted in UTF-16 code units starting at 0. A character outside the basic plane, such as an emoji, takes two units, and an editor may count lines and columns or code points instead.

How many matches can it handle?

The count goes up to 100,000 matches and the list shows the first 500. Text up to 1,000,000 characters and patterns up to 5,000 characters are accepted.