Find and Replace With Capture Groups

Use Replace mode with $1 and $<name> capture-group references to reformat matched text, with a live preview that updates as you edit the pattern or the replacement template.

Find and Replace Text Using Regex Capture Groups

Reformatting a batch of text by hand, moving a date from one order to another or stripping a prefix off a hundred log lines, is slow and error-prone the moment the batch grows past a handful of lines. A capture group turns each matched piece of a pattern into a reusable reference, and Replace mode lets you rearrange those references into a new shape while watching the exact result update as you type.

Run this check yourself in the Regex Tester & Match Debugger.

Open in the tool →

What a capture group actually captures

Parentheses inside a pattern do two things at once: they group part of the pattern together, and they capture whatever text matched that part so it can be referenced later.1 A pattern like (\d{4})-(\d{2})-(\d{2}) matched against 2026-08-13 captures three separate pieces, the year, the month, and the day, each addressable on its own even though the whole match is one contiguous string.

Named groups add a second way to reference the same captured text. Writing (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) instead captures the identical three pieces but lets the replacement template refer to them by name rather than by position, which matters once a pattern has enough groups that counting parentheses to find "group 3" becomes error-prone.1

Confirming which text landed in which group before replacing anything

Before writing a replacement template, checking Match mode's group inspector confirms each numbered or named group actually captured what you expect. If group 2 is supposed to hold the month but the inspector shows a two-digit year fragment instead, the parentheses are in the wrong place, and fixing that before switching to Replace mode saves a confusing round of debugging a replacement that looked right but used the wrong source text.

The inspector lists every group's exact character range alongside its captured text, which matters once two groups capture strings that happen to look similar, like a two-digit month next to a two-digit day. Confirming the range rather than just eyeballing the captured digits removes any ambiguity about which group is which before that ambiguity turns into a swapped field in your replacement output.

Writing a replacement template that rearranges the pieces

Replace mode's template field follows the same syntax JavaScript's own String.replace uses, so whatever produces the right result here produces the identical result in your actual code. $1 through $9 insert numbered capture groups by position, $<name> inserts a named group by its label, $& repeats the entire match, and $$ inserts a literal dollar sign when your output genuinely needs one.2

Reformatting the date example from before means writing $3/$2/$1 for the numbered version or $<day>/$<month>/$<year> for the named version, and both produce 13/08/2026 from the same input. The live preview beneath the replacement field updates on every keystroke, so a swapped group order or a missing slash shows up immediately rather than after you have already copied the wrong output somewhere else.

JavaScript's String.replace documents the full substitution set, including $& for the whole match and $$ for a literal dollar sign, and it also defines what happens when a reference is wrong: a $n or $<Name> reference pointing at a group that does not exist is inserted as literal text rather than throwing, while a group that exists but did not participate in the match is replaced with an empty string3. That silent fallback is exactly why reading the preview matters more than assuming the template was interpreted as intended.

Catching an off-by-one group reference before it ships

The most common replacement mistake is referencing the wrong group number after inserting or removing a group earlier in the pattern, since every group after the change shifts position by one. Watching the live preview while you edit the pattern itself, not just the replacement template, catches that shift the moment it happens instead of after the output silently starts producing the wrong field in the wrong place.

Deciding when a replacement should run once or everywhere

The Global flag controls how many matches a replacement touches, and getting this wrong produces two very different kinds of bug. With the flag off, only the first match in your test text gets replaced, which is correct when you are editing one specific occurrence but silently wrong the moment your real input contains more than one match you meant to catch.4

Choosing Global for a batch instead of one edit

Toggling Global on rewrites every match in the text at once, using the same template against each one independently. For a batch of log lines that all share the same date format, that difference is the entire point of using a pattern-based replace instead of a manual find-and-replace in a text editor: one template, applied consistently, across every line that matches.

Watching the live preview while toggling Global on and off against the same test text is a fast way to confirm which behavior your actual task needs before you copy the result anywhere. A preview that changes length dramatically the moment you toggle the flag is a clear sign your original test text held more matches than you had accounted for. The specification encodes the same rule: String.prototype.replace replaces more than once only for a regular expression carrying the global flag, and the dedicated replaceAll method exists as the general-purpose global replacement API5.

When to use this

Use this guide any time you need to reformat matched text using capture-group references in Replace mode, whether by numbered groups or named groups.

Examples

Reformatting a date using numbered capture groups

Before
Pattern: (\d{4})-(\d{2})-(\d{2})
Replacement: $3/$2/$1
Test text: 2026-08-13
After
The live preview shows 13/08/2026, with each numbered group inserted in its new position.

The same reformat using named capture groups

Before
Pattern: (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
Replacement: $<day>/$<month>/$<year>
Test text: 2026-08-13
After
The live preview again shows 13/08/2026, but the replacement template reads by name instead of by position.

Named and numbered groups capture the same text; only the way you reference them in the replacement differs.

Sources
  1. 1.

    MDN Web Docs, "Named capturing group: (?<name>...)," developer.mozilla.org, accessed August 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group

  2. 2.

    Jan Goyvaerts, "Reinserting Text Matched By Capturing Groups in The Replacement Text," regular-expressions.info, accessed August 2026. https://www.regular-expressions.info/replacebackref.html

  3. 3.

    Ecma International, "ECMAScript 2027 Language Specification, GetSubstitution," tc39.es, 2027. https://tc39.es/ecma262/multipage/text-processing.html#sec-getsubstitution

  4. 4.

    MDN Web Docs, "RegExp.prototype.global," developer.mozilla.org, accessed August 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global

  5. 5.

    Ecma International, "ECMAScript 2027 Language Specification, String.prototype.replaceAll," tc39.es, 2027. https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.replaceall

FAQ

The reference inserts an empty string instead of throwing an error, which mirrors exactly how JavaScript's String.replace behaves in real code. That silent behavior is also why checking the live preview matters: a typo in a group number does not fail loudly, it just quietly drops that piece from your output.

Yes. A pattern can capture some groups with plain parentheses and others as named groups, and the replacement template can reference $1 alongside $<name> in whatever combination the pattern supports, as long as each reference points at a group that actually exists in the pattern.

Check the Global flag above the pattern field. With it off, replacement stops after the first match found in your test text; toggling it on applies the same replacement template to every match in the string, not just the first one.

No. CapyToolkit's Replace mode shows the substituted result in a separate output pane below the template field; your original test text stays exactly as you pasted it, so you can adjust the template repeatedly without needing to re-paste the source text each time.

$& always refers to the entire match, not a specific captured piece inside it. It is useful when you want to wrap the whole match in something, like adding brackets around it, without needing to capture and re-reference each individual piece.