Regex Debugger — Manual

Every Regex Debugger feature: editors, eight flags, matches, replace, split, explain, code export, library, share links, and the JS engine's limits.

Back to the overview: Regex Debugger · Open the tool: www.jpkc.com/tools/regex/

This manual describes the Regex Debugger in full: every input field, every flag, the five result tabs, how matches and capture groups are shown, the library, the cheat sheet, saving and sharing, and the limits of the underlying JavaScript engine. The tool's interface is in English, so field and button names appear here exactly as you'll see them in the live tool.

Layout and flow

The interface has two columns. On the left are three stacked cards — Pattern, Test String, and the results card with the tabs Matches, Replace, Split, Explain, and Code — with the built-in Cheat Sheet on the right (below them on narrow screens). There is no run button to press: evaluation happens automatically as soon as you change the pattern, the text, the flags, or the replacement. Typing is debounced by 150 ms so the tool doesn't recompute on every keystroke; a flag click and the Enter key in the pattern field take effect immediately.

Under the hood, a RegExp object is built from your pattern and selected flags and run against the test string in a Web Worker — a separate background thread in the browser. The result appears as a counter, as a match list, and as colored highlighting in the text; when the Replace or Split tab is open, the worker also computes the replacement or the split. If an evaluation takes longer than 1.5 seconds, the tool stops it (see Time limit). A status line below the flags shows the run time in milliseconds, or the error message when something goes wrong. You switch between the result tabs by clicking or with the left/right arrow keys.

Pattern

The top editor holds your regex pattern — the bare expression, without the surrounding slashes and without trailing flags. The slashes sit fixed to the left and right of the field, and after the closing / the tool echoes the flags currently set. If your code says /\d+/g, only \d+ belongs here; you set the g via the flag toggles.

Write backslash sequences as you would in a real regular expression, so \d, \w, \b, and so on — not double-escaped as in a JavaScript string literal. You type the pattern exactly as it would appear between the slashes.

The editor (ACE) colors the parts of the pattern — escapes, character classes, parentheses, quantifiers, and operators such as |, ^, $, and . — and highlights the matching bracket. It grows with its content up to six lines and wraps long patterns. Enter doesn't insert a line break; it runs the evaluation right away.

Pasting a literal

Paste a complete JavaScript literal such as /hello/i and the tool takes it apart automatically: hello lands in the pattern field, i is set as a flag, and a short notification confirms the conversion. Escaped slashes (\/) become plain /. The flags are taken exactly as they appear in the literal — so pasting /abc/ without flags also switches g off. The conversion only happens when the whole input starts with /, only valid flag letters follow the last /, and the part in between is a valid regex. A path like /var/log/syslog is therefore left alone, whereas /var/log/ meets all the conditions and becomes the pattern var/log.

Copying the pattern

The copy button (icon, tooltip "Copy as /pattern/flags") in the Pattern toolbar puts your pattern on the clipboard in literal format: /pattern/flags. The currently selected flags come along, and any slashes in the pattern are escaped as \/ automatically — so the result drops straight into JavaScript code as a valid literal. If the pattern is empty you get a "Nothing to copy." notice instead of a copy.

The share button (tooltip "Copy a share link (pattern, flags, test string)") copies a link that carries pattern, flags, test string, and replacement. The data sits Base64url-encoded right in the link (in the #r=… part); no server stores anything. If the test string is longer than 20,000 characters, the tool leaves it out and tells you so in the confirmation message. Whoever opens the link gets exactly that state loaded; the tool then removes the #r= part from the address bar again. If the link is broken, you'll see "The share link is damaged.".

Clearing pattern and test string

The clear button (trash icon, tooltip "Clear pattern and test string (Ctrl+Z restores)") empties pattern and test string. Flags and the replacement field stay as they are. Afterward the cursor sits in the Pattern editor; Ctrl+Z brings back the content of whichever editor has focus.

Library

The Library dropdown holds 17 proven patterns, each with test text that mostly mixes valid and invalid cases:

  • E-mail address (pragmatic), URL (http/https), IPv4 address, IPv6 address (common forms)
  • ISO date (named groups), German date (dd.mm.yyyy), Time (24 h)
  • UUID, Hex color, German postal code, Semantic version, URL slug
  • Markdown link, HTML tag, Duplicate words, Trailing whitespace
  • Password strength (12+, upper, lower, digit, symbol)

One click sets pattern, flags, and test text and fills the replacement field — some entries bring a matching replacement (for example ISO date → $<day>.$<month>.$<year>, or Markdown link → HTML link); for the rest the field is cleared. Whatever you had before is overwritten.

Test String

The middle editor holds the text your pattern runs against. It is multi-line, wraps long lines, and shows line numbers, which helps when working with the line-oriented flag (m) and with longer input. Top right in the card header is the match counter: "0 matches", "1 match", or "N matches", "Timeout" after an abort, and "Error" for an invalid pattern. Every change to the text triggers a fresh evaluation after a short delay.

Flags

Below the Pattern editor sit eight toggles that together form the flag string for the RegExp object. By default only g is on. Each toggle maps exactly to the JavaScript regex flag of the same name, and each button's tooltip explains it briefly.

g — global

Finds all matches instead of just the first. On by default in the tool. Important in practice: if g is off, the match list shows only the first match and Replace only replaces the first occurrence — that's not a bug, it's the engine's normal behavior. For most debugging tasks you want g on.

i — case insensitive

Ignores letter case. Hello then also matches hello and HELLO.

m — multiline

Changes the meaning of the anchors ^ and $: they then match the start and end of each line instead of just the start and end of the whole string. Without m, ^ only matches at the very beginning. With a multi-line test string and line numbers you see the effect right away.

s — dotall

Lets the dot . also match line breaks. Without s, . matches any character except a newline; with s, that one too.

u — unicode

Turns on full Unicode processing. Needed as soon as you use Unicode escapes like \u{1F600} or Unicode property escapes like \p{L}. Without u, some sequences are interpreted differently.

v — unicode sets

The extended Unicode mode: it does everything u does and additionally allows set operations inside character classes, such as [\p{L}--[a-z]] (all letters except a–z). u and v are mutually exclusive — switch one on and the other turns off automatically. The Code tab points out that v needs a current runtime (per the tool's note: Chrome 112+, Firefox 116+, Safari 17+, Node 20+).

y — sticky

Forces a match exactly at the current position (lastIndex), not somewhere later in the string. In the tool the search starts at position 0 — if the pattern finds nothing there, the list reports "No match at position 0 (flag y only matches where the last match ended)." With g also set, every further match has to start right where the previous one ended: the tool finds an unbroken chain from the start of the text and stops at the first character where the pattern doesn't fit. A special case for tokenizer-style tasks.

d — indices

Makes the engine report the start and end position of every group (match.indices). The toggle has no effect on the match list, the highlighting, Replace, or Split: the worker always computes the group positions for highlighting anyway, and d doesn't affect what matches. It shows up in the flag display after the closing / and in what you take out of the tool: the copied literal ("Copy as /pattern/flags" button) and the share link carry the d; in the Code tab it appears in the JavaScript literal, and the PHP code gets PREG_OFFSET_CAPTURE.

Matches

The first tab of the results card shows the match list. While the pattern is empty it reads "Enter a pattern to see matches."; if a valid pattern finds nothing, "No matches." appears.

For each match the list renders an entry with:

  • Number — a running badge (1, 2, 3 …).
  • Match value — the actually matched text (match[0]), with the same background color as in the test string. An empty (zero-length) match shows as "(empty)".
  • Position — shown as pos X–Y: the start and end index of the match in the string (zero-based, end exclusive).

Clicking the head of an entry selects the match in the test string and scrolls to it — handy in long texts.

Capture groups (numbered)

If your pattern contains parentheses (…), the match entry lists each capture group below it on its own line: on the left the group number, in the color used to underline that group in the test string, next to it the captured substring. Groups that didn't take part in this match — say, the branch of an alternation that wasn't taken — show as "did not participate (undefined)". Numbering follows the order of opening parentheses — just like in JavaScript.

Named capture groups

Named groups (?<name>…) appear in the same list: after the group number comes the name as <name>, then the value. So every group shows up exactly once, with its number and its name. The tool's starting example ((?<word>\w+)) demonstrates this directly.

Highlighting in the test string

Alongside the list, the tool marks each match directly in the test string in color. Four colors rotate: matches 1, 2, 3, 4 get distinct tones, match 5 gets the first color again, and so on. So even with closely packed matches you can tell where one ends and the next begins. On top of that, capture groups are underlined in color (six rotating colors, matching the numbers in the list). On every re-evaluation the old marks are cleared and set anew.

Very many matches

The tool counts up to 100,000 matches; the first 1,000 are listed in detail and marked in the text. Beyond that, the list states how many matches weren't shown, and the status line adds "first 1,000 matches highlighted". If counting stops at 100,000, the counter gets a "+" (e.g. "100,000 matches+").

Replace

The Replace tab shows what text.replace(regex, replacement) does to your test string. You type the replacement into the Replacement field; the result appears below in a read-only editor and can be copied with Copy result. The JavaScript replacement patterns are allowed:

  • $1, $2 … — content of the numbered group
  • $<name> — content of the named group
  • $& — the whole match
  • $` and $' — the text before or after the match
  • $$ — a literal dollar sign

Above the result the tool tells you how much was replaced: "All matches replaced." with flag g, otherwise "Without flag g only the first match is replaced.". The replacement is only computed while the Replace tab is open. The field's content also feeds into the Code tab.

Split

The Split tab shows the result of text.split(regex) as a numbered list starting at 0 — the same indices you use in code. Empty parts show as "(empty string)". If your pattern contains capture groups, their contents end up in the result just as in JavaScript; a group that didn't participate shows as "undefined". The split is only computed while the Split tab is open. At most 5,001 parts are shown; anything beyond that is cut off without notice.

Explain

The Explain tab breaks your pattern into its building blocks and explains each in one line of plain English — literals, escapes (\d, \p{…}, \u{…}, backreferences), character classes including ranges, quantifiers marked greedy or lazy, anchors, alternation, groups, and lookarounds. Group contents are indented by nesting depth, and each group gets its number and, if it has one, its name. The explanation takes the flags into account: with m, ^ reads "start of a line", without it "start of the text"; with s, . matches "any character, including newlines". Quantifier binding becomes visible too: in abc+, the + repeats only the c.

Code

The Code tab turns pattern, flags, and replacement into ready-made sample code. Under Language you pick JavaScript, PHP (PCRE), or Python (re); Copy code copies the result. The code contains a loop over all matches (with g) or a search for the first match (without g) and — if the Replacement field isn't empty — the matching replacement line.

  • JavaScript — the pattern as a literal (with escaped slashes), plus matchAll() or match() and replace().
  • PHP (PCRE) — the pattern with a delimiter that doesn't occur in it (/, ~, #, %, @, or !), the flags i, m, s as modifiers, and u whenever u/v is set or the pattern contains \u… or \p{…}. \u… and \u{…} become \x{…}. Plus preg_match_all() or preg_match() and preg_replace() (limit 1 without g); in the replacement, $<name> becomes the group number and $& becomes $0.
  • Python (re) — re.compile() with re.IGNORECASE, re.MULTILINE, re.DOTALL; named groups become (?P<name>…), \k<name> becomes (?P=name). Plus finditer() or search() and sub() (count=1 without g); $1, $<name>, and $& become \g<…>, and $$ becomes a plain $. \u{…} in the pattern becomes \U with eight hex digits.

Above the code, yellow notes appear whenever something doesn't carry over 1:1 — for example: no $`/$' in PHP and Python replacements, no equivalent for v in PCRE and Python, no equivalent for y in Python (for PCRE the tool suggests the A modifier or \G), [^] being JavaScript-only, $ in PCRE also matching before a final line break (modifier D), variable-length lookbehind, no \p{…} in Python's re module, and the Unicode behavior of \d/\w in Python 3 (re.ASCII).

Error display

If your pattern is syntactically invalid (e.g. an unbalanced parenthesis or an invalid quantifier), the engine can't build a RegExp. Then the JavaScript engine's original error message appears in the status line below the flags, the match list stays empty, and the counter switches to "Error". The message is the unmodified browser message (e.g. "Invalid regular expression: …") — it often points right at the problem spot.

Time limit (timeout)

If an evaluation runs longer than 1.5 seconds, the tool terminates the worker. The counter shows "Timeout", and the status line explains the likely cause: catastrophic backtracking from nested quantifiers such as (a+)+ or (\w*)* on text that almost matches. The page stays usable throughout; as soon as you change the pattern or the text, a new evaluation starts. An evaluation that's still running but already outdated is cancelled immediately instead of waiting out its time limit.

Cheat Sheet

On the right sits a collapsible reference (accordion) that keeps the most important regex building blocks as short tables. Every building block is clickable ("click to insert"):

  • Characters — ., \d, \D, \w, \W, \s, \S, \n, \t, \..
  • Quantifiers — *, +, ?, {3}, {3,}, {2,5} plus the lazy variants *? and +?.
  • Groups — (), (?:), (?<name>), backreferences \1 and \k<name>, alternation |.
  • Anchors — ^, $, \b, \B.
  • Lookaround — (?=), (?!), (?<=), (?<!).
  • Character Classes — [abc], [^abc], [a-z], [A-Za-z], [0-9].
  • Unicode (flag u or v) — \p{L}, \p{Lu}, \p{N}, \p{Script=Greek}, \p{Emoji_Presentation}, \u{1F600}.
  • Replacement — $1, $<name>, $&, $`, $', $$.
  • Flags — the eight flags with a short explanation.

Clicking a pattern building block inserts it at the cursor position in the Pattern editor; for groups and lookarounds the cursor lands right between the parentheses. Building blocks from Replacement go into the replacement field, and the tool switches to the Replace tab. Entries under Flags toggle the respective flag. The footer reminds you that the tool uses JavaScript syntax and that the Code tab points out the differences to PHP and Python.

Saving and sharing

The tool automatically keeps your working state in your browser's localStorage: pattern, flags, test string, replacement, and the open tab. After a reload everything is back — with one exception: if you switched all flags off, the tool starts with g again. The same goes for a share link without flags. Test strings over 200,000 characters aren't saved, to keep the storage small. If you open a share link, its content takes precedence — and it also replaces your saved state, because the tool saves the loaded link content right away. To keep your own state, copy a share link of it first. With neither a link nor a saved state, the tool starts with the example (?<word>\w+), the sentence "Hello World! This is a regex test with 123 numbers.", and the replacement [$<word>].

Engine and limits

The debugger is purely client-side and uses the browser's native JavaScript RegExp API. There's no server call, no data transfer; pattern and text stay on your device. From that follow the key facts and limits:

  • You're testing the JS engine. Results apply 1:1 to JavaScript/Node.js/TypeScript — but not necessarily to PCRE (PHP), Python re, Go, or .NET. The Code tab translates the pattern to PHP and Python and names the most important differences; more are in the tips.
  • Eight flags. g/i/m/s/u/v/y/d — all JavaScript flags. u and v can't be set at the same time.
  • JavaScript feature set. Available: named groups, lookahead and lookbehind, backreferences, and (with u or v) Unicode property escapes. Not available: PCRE quirks like atomic groups, possessive quantifiers, recursion, \A/\Z/\z, or POSIX classes [[:alpha:]].
  • Zero-length matches (e.g. \b or a* at empty spots) are handled correctly: after an empty match the tool moves on — with u/v past whole Unicode characters such as emoji — and so prevents the infinite loop a global match on such patterns would otherwise trigger.
  • Catastrophic backtracking is caught. A pathological pattern (nested quantifiers like (a+)+$) no longer freezes the tab: after 1.5 seconds the tool stops and reports "Timeout". That doesn't fix the pattern itself, though — in your code it would still hang. Details and remedies in the tips.
  • Size limits. Up to 100,000 matches are counted, the first 1,000 listed and marked; Split shows at most 5,001 parts; share links carry test strings up to 20,000 characters, local storage up to 200,000 characters.

For the introduction, the audiences, and the big picture, see the overview page. Concrete walkthroughs are in the examples. You can try all of it directly in the tool.