flashman
← All posts

Regex named group display debugging

Debug a named capture that looks empty by comparing the tester's numbered group list with those names on the match, and by keeping that pattern global.

2026-10-18 · 6 min read · Rahul Chitturi

  • regex
  • javascript
  • debugging

A named capture is still a numbered capture. (?<id>\d+) is group 1, and the match object also stores that text under the name id. Flashman's regex tester prints the match, the index, and the numbered slots from the match array. It does not print the names, and it does not print the index pairs added by the d flag.

On the text a12 b34, the pattern (?<id>\d+) with flag g lists two lines: @1 with groups ["12"], and @5 with groups ["34"]. The name id is on the match in JavaScript and is absent from the panel. An empty-looking name in a review is often a name the panel never had room to show.

Keep the pattern global or matchAll throws

The tester calls matchAll. That method requires the global flag. (?<id>\d+) with an empty flag string throws String.prototype.matchAll called with a non-global RegExp argument. The d flag alone throws the same way. dg runs, and the engine then has index pairs, but the panel still shows only the numbered groups.

A non-capturing group adds no slot. (?:\d+) with g on a12 matches 12 and prints no groups list. If a pattern was supposed to capture and the groups list is missing, the parentheses are non-capturing, or the flags never included g and the panel is showing the exception instead.

  • Put g on every pattern you send to the tester.
  • Read groups as numbered slots, in source order.
  • Write the name next to the slot in the ticket.
  • Do not expect the d flag's indexes to appear.

Null in a slot is not an absent name

(?<word>\w+)-(?<num>\d+) with g on user-12 prints groups ["user","12"]. The names word and num sit on those two slots in that order. The panel's array is enough once you have written the names down beside it.

(?<a>a)|(?<b>b) with g on ab prints ["a",null] and then [null,"b"]. The numbered list has one slot per pair of parentheses, and the alternative that did not match is null. The named object on the same match is {"a":"a"} and then {"b":"b"}: the name that did not participate is missing, not null. Those are different shapes. Copying the panel's null into a names map invents a key the engine did not set.

Duplicate names fail before they match

(?<a>a)|(?<a>b) throws Invalid regular expression and Duplicate capture group name with gu and with gv. This runtime does not accept the repeated name in either Unicode mode. Change the second name, or drop the name, before you compare match lists.

Use the regex tester for the numbered list, the JSON formatter to store the pattern, the flags, the text, and the names you assigned to each slot, and diff when two services disagree about which alternative matched. The panel line and the name map are both part of the fixture. One of them is not a substitute for the other.

Try these tools