Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at the best features of ES2018.
Numbered Capture Groups
Numbered capture groups lets us take apart a string with a regex.
This is the old way to get group matches.
A regex that matches a string returns a matched object.
Then we can get each part by its index.,
For instance, we can write:
const PHONE_REGEX = /([0-9]{3})-([0-9]{3})-([0-9]{4})/;
const matchObj = PHONE_REGEX.exec('123-456-7890');
We have 3 capture groups. 2 with 3 digits and one with 4 digits.
Then we can get each group by its index.
The problem with named capture groups is that we’ve to count parentheses.
We’ve to know what the groups are about from the regex pattern.
And we’ve to change the code if we change the regex.
Named Capture Groups
ES2018 gives us a new way to get a group match.
For instance, we can write:
const PHONE_REGEX = /(?<areaCode>[0-9]{3})-(?<officeCode>[0-9]{3})-(?<number>[0-9]{4})/;
const matchObj = PHONE_REGEX.exec('123-456-7890');
console.log(matchObj.groups)
We added the names to the groups.
Then we can get the matches in the groups
property.
So we’ll get:
{ areaCode: "123", officeCode: "456", number: "7890" }
as the value of macthObj.groups
.
This means that we can destructure the matches:
const PHONE_REGEX = /(?<areaCode>[0-9]{3})-(?<officeCode>[0-9]{3})-(?<number>[0-9]{4})/;
const matchObj = PHONE_REGEX.exec('123-456-7890');
const {
areaCode,
officeCode,
number
} = matchObj.groups;
Named captured groups are good because it’s easier to identify the capture group.
The matching code is descriptive since the ID describes what it’s capturing.
And we can change the pattern without changing the matching code.
The names make the pattern easier to understand.
Backreferences
We can reference a matching group by its name in a regex.
For instance, we can write:
const REGEX = /^(?<word>[abc]+)k<word>$/;
const matchObj = REGEX.exec('abcabc');
console.log(matchObj.groups)
Then get the matches with marchObj.groups.words
.
word
has the same pattern.
replace()
We can use replace
with named capture groups.
For instance, we can write:
const PHONE_REGEX = /(?<areaCode>[0-9]{3})-(?<officeCode>[0-9]{3})-(?<number>[0-9]{4})/;
console.log('123-456-7890'.replace(PHONE_REGEX,
'$<areaCode>$<officeCode>$<number>'))
We called replace
with our regex and a string with the pattern that we want to format the string to.
We just get the named capture groups and combined them without spaces.
So we get:
'1234567890'
returned.
It also takes a callback that has the groups as one of the parameters:
const PHONE_REGEX = /(?<areaCode>[0-9]{3})-(?<officeCode>[0-9]{3})-(?<number>[0-9]{4})/;
console.log('123-456-7890'.replace(PHONE_REGEX,
(g0, ac, oc, num, offset, input, {
areaCode,
officeCode,
number
}) => `${areaCode}${officeCode}${number}`))
The last parameter has the groups.
Also, ac
, oc
, and num
are the groups.
We return a new string so that it’ll be the string returned by replace
.
g0
has the full string.
offset
specifies where the matches are found.
input
has the complete input string.
Named groups that don’t match
If we have named groups that don’t match, then the property will be undefined
in the groups
property.
Conclusion
Named capture groups are handy for naming matches so we can understand them easier and won’t have to change the matching code.