SoFunction
Updated on 2025-03-04

JavaScript regular naming grouping [Recommended]

Preface

In the past, we were just used to accessing the regular matched groups through array subscripts, but when the groups reach 4 or 5, it would be very troublesome to identify them. V8 has long implemented the regular naming grouping proposal, but we rarely use it. This article will introduce the regular naming grouping of JS.

Past practices

Suppose we want to use regular matches to a date, in the past we would do this:

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

Here are a few disadvantages:

  • To find a grouped position, you have to go to the brackets, and sometimes nesting it can be more troublesome.
  • When students who maintain the code read, they must find the corresponding brackets in the rules based on the subscript, and read the rules in the brackets again to know the meaning.
  • When you adjust the number, order, or nesting of regular capture groups, you must also make adjustments to the following code.

All these problems can be solved by regular named grouping.

How to play now

Now you just need to give the group a named identifier:

(?<year>\d{4})

Here, we tagged the previous capture group #1 with the variable year. The name must be a legal JavaScript identifier. After matching, you can access the captured string by accessing.

Let's rewrite the previous code by naming grouping:

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = ; // 1999
const month = ; // 12
const day = ; // 31

If there is a named group in the regular, the matching result will have an additional group attribute, which contains the capture results of all named groups. In conjunction with the use of the above-deconstruction method, it is another clear stream:

const {groups: {day, year}} = RE_DATE.exec('1999-12-31');
(year); // 1999
(day); // 31

Of course, even if you use named grouping, the returned results can still be accessed through the previous array subscript:

const year2 = matchObj[1]; // 1999
const month2 = matchObj[2]; // 12
const day2 = matchObj[3]; // 31

Naming grouping has the following advantages:

  • It is easier to find the "ID" of the group.
  • The matching code becomes self-descriptive because the ID of the packet describes the captured content.
  • If you change the order of groupings, you do not have to change the matching code.
  • The names of groups also make regular expressions easier to understand, as you can see directly what each group is for.

Backreferences

Backreference named grouping\k<name>

See the following example of matching repeated words:

const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc'); // true
RE_TWICE.test('abc!ab'); // false

At the same time, you can also use the previous backreference method:

const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc'); // true
RE_TWICE.test('abc!ab'); // false

replace( )

The string method replace() supports named grouping in two ways:

Method one

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
('1999-12-31'.replace(RE_DATE,
 '$<month>/$<day>/$<year>'));
 // 12/31/1999

If replace does not necessarily return a new splice string directly, then you can take a look at the following method:

Method 2

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
('1999-12-31'.replace(
 RE_DATE,
 (g, y, m, d, offset, input, {year, month, day}) =>
  month+'/'+day+'/'+year));
 // 12/31/1999

Look at the callback of the replace, and it is so nervous that it is not useful. Let’s take a look at the simpler way to write it:

('1999-12-31'.replace(RE_DATE,
 (...args) => {
  const {year, month, day} = (-1)[0];
  return month+'/'+day+'/'+year;
 }));
 // 12/31/1999

Here, we use the spread operator to directly take the last parameter, and then connect to the previous deconstruction method, and the result is another clear stream.

No matching result for named grouping?

If the optional named group does not match, its attribute value is set to undefined, but the key is still present:

const RE_OPT_A = /^(?<as>a+)?$/;
const matchObj = RE_OPT_A.exec('');
// We have a match:
(matchObj[0] === ''); // true
// Group <as> didn't match anything:
( === undefined); // true
// But property as exists:
('as' in ); // true

Exception

There cannot be duplicates for group names:

/(?<foo>a)(?<foo>b)/ // SyntaxError: Duplicate capture group name

Backreferences to a non-existent group name:

/\k&lt;foo&gt;/u // SyntaxError: Invalid named capture referenced
/\k&lt;foo&gt;/.test("k&lt;foo&gt;") // true, No Unicode For backward compatibility,k The front \ Will be discarded

Refer to a non-existent group in the replacement string of the reapplce() method:

"abc".replace(/(?&lt;foo&gt;.*)/, "$&lt;bar&gt;") // SyntaxError: Invalid replacement string
"abc".replace(/(.*)/, "$&lt;bar&gt;") // "$&lt;bar&gt;",Backward compatibility when no named grouping is included

at last

  • Chrome 60 supports named grouping
  • Handle compatibility issues through babel plugin

babel-plugin-transform-modern-regexp

Summarize

The above is the JavaScript regular naming group introduced by the editor. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!