Regex Tester

Free regex tester, regex checker and regular expression tester for JavaScript (ECMAScript) patterns: watch every match highlighted live as you type, inspect named and numbered capturing groups, preview a Replace, get a copy-ready JS snippet, and share a link — all in your browser, with nothing uploaded.

Matching…

Matches

JavaScript

Regex cheat sheet (click a token to insert it into the pattern)
Pattern, flags and test text are encoded after # in the URL, so a link works with no server. Nothing is uploaded.

This tests JavaScript (ECMAScript) regular expressions, the flavor used by browsers and Node.js. Matching runs entirely in your browser, in a background worker with a 1-second timeout, so a runaway pattern can't freeze the page. Nothing you type is uploaded, logged or saved.

How to test a regex

  1. Type or paste a pattern between the two / characters, for example (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}).
  2. Tick the flags you need. g (global) finds every match instead of stopping at the first, which most testing needs turned on.
  3. Paste the text to test against. Matches are highlighted live, and the Matches panel lists each one's position, full text, and any capturing groups.
  4. Switch to Replace to write a replacement ($1, $<name>, $&) and see the result before you use it in code.
  5. Copy the ready-made /pattern/flags literal or new RegExp(...) call from the snippet box, or press Copy share link to send the whole thing to someone else.

If the pattern is invalid, the box outlines in red and the exact error from JavaScript's own RegExp constructor appears above the test string — the same message your code would throw.

Regex cheat sheet

The tester has a click-to-insert cheat sheet under the tool (press Regex cheat sheet to open it). The tokens you'll use most:

TokenMatches
.Any character except line break
\dDigit (0–9)
\DNot a digit
\wWord character (letter, digit, _)
\WNot a word character
\sWhitespace
\SNot whitespace
^Start of string (or line, with m)
$End of string (or line, with m)
\bWord boundary
\BNot a word boundary
*0 or more
+1 or more
?0 or 1 (optional)
{2,4}Between 2 and 4 times

Groups and lookaround: (...) capturing, (?<name>...) named capturing, (?:...) non-capturing, (?=...) lookahead, (?!...) negative lookahead, (?<=...) lookbehind, (?<!...) negative lookbehind.

JavaScript regex flags explained

FlagNameWhat it does
gGlobalFind all matches instead of stopping after the first.
iIgnore caseMatch letters regardless of case.
mMultiline^ and $ match the start/end of each line, not just the whole string.
sDot all. also matches line breaks.
uUnicodeTreat the pattern as Unicode code points; enables \u{...} and stricter escape rules.
vUnicode setsUpgraded Unicode mode with set operations in character classes, e.g. [\p{L}--[a-z]]. Cannot combine with u.
yStickyMatch only starting at lastIndex, never search ahead.
dIndicesAlso report the start/end index of every captured group.

The tester only shows d and v as options when your browser supports them (both are recent additions to the language); g, i, m, s, u and y work everywhere.

Named vs numbered capturing groups, and how replace uses them

Matching (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (flag g) against:

Launch: 2026-09-25. Renewal: 2027-01-01.

finds 2 matches, each with three named groups: year, month and day. Replacing with $<day>/$<month>/$<year> gives:

Launch: 25/09/2026. Renewal: 01/01/2027.

The same replacement with numbered groups instead of named ones would be $3/$2/$1 — named groups just make it obvious which is which once a pattern has more than one or two. As a JS snippet:

const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
// or: const regex = new RegExp("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})", "g");
text.replace(regex, "$<day>/$<month>/$<year>");

Common regex examples

PatternRegexTest textMatches
Email address/[\w.+-]+@[\w-]+\.[\w.-]+/gContact [email protected] or [email protected] for help.[email protected][email protected]
IPv4 address/\b(?:\d{1,3}\.){3}\d{1,3}\b/gServer at 192.168.1.10, backup 10.0.0.5, not 999.192.168.1.1010.0.0.5
ISO date (YYYY-MM-DD)/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/gLaunch: 2026-09-25. Renewal: 2027-01-01.2026-09-252027-01-01
US phone number/\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/gCall (415) 555-2671 or 415.555.9834 today.(415) 555-2671415.555.9834
Hex color/#[0-9a-fA-F]{3,6}\b/gBrand colors: #0b6e4f, #FFF and #3fbf8f.#0b6e4f#FFF#3fbf8f
Simple HTML tag/<\/?[a-z][a-z0-9]*\b[^>]*>/gi<p class="a">Hi <br/></p><p class="a"><br/></p>

These are starting points, not production-ready validators — the email pattern above, for instance, accepts plenty of strings that aren't deliverable addresses. For anything user-facing (email, phone, postal code), a working regex plus an actual delivery check (send a code, call an API) beats a "perfect" pattern that doesn't exist.

Why is my regex slow? (Catastrophic backtracking)

Some patterns can make the regex engine try an exponential number of ways to fail before giving up. The classic example is nested repetition, like /(a+)+$/: against a string of 28 a's followed by a character that breaks the match, the engine backtracks through every way to group those a's into one-or-more chunks before it can finally say "no match", and the work roughly doubles with each extra character.

Press Slow pattern in the tool to load exactly that example against aaaaaaaaaaaaaaaaaaaaaaaaaaaa! and watch what happens: instead of the tab freezing, matching runs in a Web Worker with a 1-second timeout. If it's hit, the worker is terminated and replaced and you see "Pattern took too long: possible catastrophic backtracking" instead of a hung page. The fix is usually to make the repeated part more specific (so there's only one way to split the input) or restructure the pattern, for example a+$ or (?>a+)+$ where the engine supports atomic groups (JavaScript doesn't, yet — a+$ is the practical fix here).

JavaScript vs PCRE vs Python regex differences

"Regex" isn't one language — it's a family, and the differences matter once you copy a pattern between them:

  • Named groups: (?<name>...) in JavaScript and .NET; (?P<name>...) in Python and PCRE. Compiling (?P<year>\d+) here fails with: Invalid regular expression: /(?P<year>\d+)/: Invalid group — exactly what your JS code would throw.
  • Lookbehind: supported in JavaScript (since 2018), Python and PCRE, but only fixed-width in some older PCRE builds; JavaScript's is unrestricted-width.
  • POSIX classes like [[:alpha:]] work in PCRE but aren't recognized by JavaScript; use \p{L} with the u flag instead.
  • Possessive quantifiers (a++) and atomic groups ((?>...)), both used in PCRE to avoid catastrophic backtracking, don't exist in JavaScript.
  • Backreferences and flags mostly agree, but Python's re.VERBOSE/re.X (ignore whitespace and allow comments in the pattern) has no JavaScript equivalent.

regex101.com lets you switch the "flavor" it tests against (PCRE, JavaScript, Python, and more), which is worth using when you need to match what a non-JS backend will actually run. This tool is deliberately narrower and only tests the one flavor your browser and Node.js use.

More developer tools

  • JSON formatter & validator: format, minify or validate a JSON string you pulled out with a regex.
  • URL decode: decode a percent-encoded value before you write a pattern against it.
  • Base64 decode: for Base64 text found inside a larger string you're testing.
  • JWT decoder: read a token's JSON payload, then check individual claims with a regex.

Frequently asked questions

How do I test a regex?

Type or paste your pattern between the two slashes at the top, tick any flags you need (g for all matches, i to ignore case, and so on), and paste the text to test in the box below. Matches are highlighted as you type, and the panel on the right lists each one with its index and any capturing groups. Switch to Replace to preview what String.replace() would produce instead of just finding matches.

Why is my regex invalid?

Every pattern is compiled with JavaScript's own RegExp constructor, so the error you see is the exact one your code would throw: an unterminated group ((unterminated), an unescaped special character, a bad backreference, or (with the u or v flag) a stricter rule about which characters can be escaped. The pattern input is outlined in red and the message appears above the test string until you fix it.

What do the regex flags g, i, m, s, u, y, d and v mean?

g (global) finds every match instead of stopping at the first; i ignores case; m makes ^ and $ match the start/end of each line; s lets . match line breaks too; u treats the pattern as Unicode code points and enables \p{...} and \u{...}; y (sticky) only matches starting exactly at the current position; d also reports the start/end index of each group; v is a newer, stricter Unicode mode with set operations in character classes and cannot be combined with u. The tester only shows d and v when your browser supports them.

What's a named capturing group, and how is it different from a numbered one?

Every (...) in a pattern is a numbered group: $1, $2, and so on, in the order they open. Writing (?<name>...) instead also gives that group a name, so you can use $<name> in a replacement or match.groups.name in code, which stays readable when a pattern has several groups. (?:...) is neither — it groups a piece of the pattern (for example for a|b inside it) without capturing or numbering it at all.

Why is my regex slow, or why does the page say a pattern took too long?

That's catastrophic backtracking: a pattern with nested repetition, like (a+)+$, can force the engine to try an exponential number of ways to split the input before it can say "no match" — a string with 30 characters can already take longer than the page can wait. Matching here runs in a background worker with a 1-second timeout; if it's hit, the worker is stopped and restarted and you get a plain warning instead of a frozen tab. The usual fix is to make the repeated part more specific (so fewer split points are possible) or use a non-capturing, non-backtracking construction. Press Slow pattern above to see it happen safely.

Is JavaScript regex the same as PCRE, Python's re, or the one in regex101?

No — they're closely related but not identical, which is why this tool is explicit that it only tests JavaScript (ECMAScript) regex, the flavor used by browsers and Node.js. Named groups are written (?<name>...) in JavaScript and .NET, but (?P<name>...) in Python and PCRE: compiling "(?P<year>\d+)" here fails with "Invalid regular expression: /(?P<year>\d+)/: Invalid group", exactly as it would in your own JS code. Lookbehind, POSIX character classes, possessive quantifiers and recursive patterns also differ across flavors — a pattern that works on regex101 set to PCRE or Python is not guaranteed to work in JavaScript, and vice versa. See the comparison below.

Is anything I type sent to a server?

No. Your pattern and test string are matched entirely in your browser (in a Web Worker, so a slow pattern can't freeze the tab), and nothing is uploaded, logged or saved. Only which flags and mode (Test or Replace) are pressed live in the page while it's open; they aren't written to storage. The only way your text leaves the browser is if you press Copy share link, which puts the pattern, flags and test text into the URL after # for you to send yourself.

How do I use $1, $<name> and $& in a replacement?

In Replace mode (and in String.replace() in your own code), $1, $2… insert what numbered groups matched, $<name> inserts a named group, $& inserts the whole match, and $$ inserts a literal dollar sign. For example, replacing (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) in "Launch: 2026-09-25. Renewal: 2027-01-01." with $<day>/$<month>/$<year> gives "Launch: 25/09/2026. Renewal: 01/01/2027.".

What is the difference between the g and y (sticky) flags?

Both let a regex find more than one match by repeatedly calling exec() and advancing lastIndex. g searches forward from lastIndex for the next match anywhere in the rest of the string. y (sticky) only succeeds if a match starts at exactly lastIndex — useful for hand-written tokenizers that consume a string piece by piece, where a match "further along" would mean something went wrong. A pattern can have both, which behaves like g but still refuses to skip ahead.

Can I share a regex pattern and test string with someone else?

Yes. Press Copy share link: the pattern, flags, test string (shortened if it is very long), and, in Replace mode, the replacement, are encoded into the URL after the #. Opening that link loads the same pattern and text back into the tester, with nothing round-tripped through a server, because a URL fragment (the part after #) is never sent in an HTTP request.

This tool tests JavaScript (ECMAScript) regular expressions in your browser. Other languages and flavors (PCRE, Python's re, .NET) can behave differently for the same pattern, so check against the runtime you actually ship before relying on it. Spotted a wrong result? Tell us. Last reviewed .