Regex tester and explainer

Type a pattern and some text. RegexShelf runs it on a real engine in a Web Worker, highlights every match, lists the groups and their positions, and explains each part of the pattern in plain English. Your text never leaves the browser.

Flags

Highlighted matches

 

Matches, groups and indices

What the pattern means, token by token

Flavor differences that apply to this pattern

How to use

  1. Choose the flavor. JavaScript, PCRE2 and Go run on real engines; Python and Java show their differences from the cheat sheet but do not execute. Each flavor has its own flag checkboxes.
  2. Type the pattern without surrounding slashes. Syntax errors come straight from the engine, so the message is the one your own program would give you.
  3. Paste the test text. Matches are highlighted as you type; an empty match is drawn as a thin red bar. Switch the g flag off to see only the first match.
  4. Read the matches table for each match's text, its [start, end) position and every group, including named groups and groups that did not take part. Read the explanation to see what each token does, and the flavor differences panel for constructs in your pattern that behave differently elsewhere.
  5. Use Copy share link to put the pattern, flavor, flags and text into the address, so someone else opens exactly what you see. The time limit control sets how long a run may take before its Worker is terminated.

Worked examples

The expected values on this page were counted by hand before they were compared with the engine, and the automated tests run each example again.

Named groups and indices

/(?<year>[0-9]{4})-(?<month>0[1-9]|1[0-2])-(?<day>0[1-9]|[12][0-9]|3[01])/gd on Released 2026-10-02, patched 2026-10-09; the typo 2026-13-45 does not match.

Matches (UTF-16 offsets, end exclusive): [9, 19), [29, 39).

Two matches, at offsets 9 to 19 and 29 to 39. The third date has month 13, which neither 0[1-9] nor 1[0-2] accepts. Each match carries three named groups (year, month, day), and with the d flag the tester also knows where each group sits.

Lazy against greedy

/<.+?>/g on <b>bold</b> and <i>italic</i>

Matches (UTF-16 offsets, end exclusive): [0, 3), [7, 11), [16, 19), [25, 29).

The lazy +? stops at the first ">" it can, so each tag is its own match: four matches. With the greedy <.+> the same text gives one match from offset 0 to 29, because .+ first runs to the end of the text and then gives back only as much as it must.

Empty matches

/x*/g on abxd

Matches (UTF-16 offsets, end exclusive): [0, 0), [1, 1), [2, 3), [3, 3), [4, 4).

x* can match nothing, so it matches at every position: empty at 0 and 1, the single x at 2 to 3, empty at 3 (right after the x, before d) and empty at 4 (the end). The tester draws empty matches as a thin red bar. Switch the flavor to Go and the empty match at 3 disappears, because Go ignores an empty match that abuts the previous match.

Limits & gotchas

  • Go is Go, not RE2. The "Go" flavor runs Go's own regexp package, which uses RE2 syntax and has the same linear-time guarantee but is a separate implementation. The RE2 syntax wiki is cited for syntax; the C++ library itself is not run.
  • Python and Java are not executed. No real Python or Java engine runs in this page. Their entries in the cheat sheet come from their documentation, and rows marked "observed" were checked once on Python 3.13.5 or JDK 17 on a developer machine, which is not the version you may use.
  • The explainer is JavaScript-first. It tokenizes JavaScript syntax. For other flavors, read its output together with the flavor notes.
  • PCRE2 group positions. The WebAssembly wrapper returns each group's text but not its offsets, so the PCRE2 table shows group text without positions. JavaScript and Go show both.
  • Time limits are a safety net, not a benchmark. The time shown is measured in your browser on your machine, including engine start-up the first time. A pattern that is stopped is not necessarily wrong, just too slow for the limit you chose.
  • Browser support. The Worker is an ES module worker, which current Chrome, Edge, Firefox and Safari support. Inline modifiers such as (?i:...) depend on your browser version (MDN lists them as newly available in 2025).

FAQ

Is the pattern or text I type sent to a server?

No. The pattern runs in a Web Worker inside your browser tab, and the explanation is built by JavaScript on the page. The share link keeps your pattern, flags and text after a # sign, and browsers do not send that part of an address to a web server. The only files the page downloads are its own static scripts, plus the PCRE2 or Go engine file if you choose those flavors.

Which flavors does it actually run?

Three. JavaScript uses your browser's own RegExp. PCRE2 uses a WebAssembly build of PCRE2 10.48. "Go" uses Go 1.24's standard regexp package compiled to WebAssembly; it follows RE2 syntax but it is Go's implementation, not Google's C++ RE2 library. Python and Java are listed with documented differences only, and the tester says "not executed" for them rather than guess.

What happens if my pattern takes too long?

Each run has a time limit (2 seconds by default). If the Worker has not answered when it expires, the page terminates the Worker and shows a message that the pattern was stopped. Nothing freezes. Catastrophic backtracking, such as (a+)+$ on a long string of a's ending in b, is the usual cause.

Why do match positions differ from the byte offsets in my programming language?

The tester reports UTF-16 code-unit offsets for every flavor, the same numbers a JavaScript string index uses. Go reports UTF-8 byte offsets internally and the page converts them. A character outside the Basic Multilingual Plane, such as an emoji, counts as two units.

Does the explainer understand PCRE2, Python or Go syntax?

It is written for JavaScript syntax and checked against the browser's RegExp. Constructs that exist only in other flavors (atomic groups, inline flags, (?P<name>...), comments) are recognised and labelled as foreign, but tokens that exist in several flavors are explained with their JavaScript meaning, and the "Flavor differences" panel below the explanation lists where other flavors disagree.

Sources

  1. MDN: Regular expressions (reference) Used for: List of flags (d g i m s u v y), the groups of syntax, and which syntaxes are assertions.
  2. MDN: RegExp Used for: Constructor and flags, instance properties.
  3. MDN: RegExp.prototype.exec() Used for: Result array, index, groups, indices with the d flag, lastIndex behaviour with g and y.
  4. MDN: Named capturing group: (?<name>...) Used for: Names must be unique within a pattern, except in different alternatives; groups object; unmatched named group is undefined.
  5. MDN: Capturing group: (...) Used for: Numbering by opening parenthesis, undefined for unmatched groups, last-iteration capture rule.
  6. MDN: Quantifier Used for: Greedy and lazy quantifiers, {n}, {n,}, {n,m}, no spaces inside braces, braces as literals in Unicode-unaware mode.
  7. MDN: Wildcard: . Used for: . excludes line terminators unless the s flag is set; code units vs code points with the u flag.
  8. MDN: Input boundary assertion: ^, $ Used for: ^ and $ are the start and end of input, or of each line with the m flag.
  9. MDN: Worker: terminate() Used for: terminate() stops a Worker immediately without letting it finish.
  10. PCRE2: pcre2pattern Used for: Syntax and semantics: groups, named groups, lookbehind rules, atomic groups, possessive quantifiers, \d \s \w with and without UCP, dollar and newline handling, \A \Z \z.
  11. PCRE2: pcre2api Used for: Match limit (PCRE2_ERROR_MATCHLIMIT), default newline, DOLLAR_ENDONLY, pcre2_substitute replacement syntax ($1, ${1}, $<name>, $0 or $&).
  12. npm / GitHub: pcre2-wasm 10.48.0 (MIT) Used for: The WebAssembly build of PCRE2 10.48 this site runs. Pinned exactly; its license and the PCRE2 BSD license text ship in the package.
  13. Go: regexp/syntax Used for: Full syntax table; no lookaround or backreferences; \d \s \w are ASCII-only; $ is \z; (?P<name>) and (?<name>); repetition limit 1000; \A and \z.
  14. Go: regexp package Used for: Linear-time guarantee, leftmost-first semantics, Expand template syntax ($1, ${name}, $name longest-name rule).
  15. Google RE2: RE2 Syntax (wiki) Used for: RE2 syntax with explicit NOT SUPPORTED markers: lookaround, backreferences, possessive quantifiers, \Z, atomic groups.
  16. Python docs: re: Regular expression operations (3.13) Used for: Syntax, (?P<name>), atomic groups and possessive quantifiers (3.11+), fixed-length lookbehind, Unicode \d \s \w, $ before trailing newline, \A \Z, re.sub replacement syntax, inline flags at start only (3.11+).
  17. Oracle (Java SE 21): java.util.regex.Pattern Used for: Construct table, \d \s \w without UNICODE_CHARACTER_CLASS, possessive and atomic constructs, named groups, line terminators and $, \A \Z \z.

Every document above was opened and read on 2026-10-02. Documentation changes; if a page here disagrees with the current docs, trust the docs and tell us.