Група захоплення: (...)
Група захоплення групує підпатерн, даючи змогу застосувати до всієї групи квантор, або застосувати в ній диз'юнкції. Вона запам'ятовує інформацію про збіг з підпатерном, щоб на цей збіг можна було пізніше посилатися за допомогою зворотного посилання та звертатися до цієї інформації за допомогою об'єкта результатів збігу.
Якщо результат збігу з підпатерном – не потрібен, слід натомість використовувати незахоплювальну групу, що покращує продуктивність та уникне неприємностей при рефакторингу.
Синтаксис
(патерн)
Параметри
pattern
Патерн, що складається з будь-чого, що можна використовувати в літералі регулярного виразу, включно з диз'юнкцією.
Опис
Група захоплення діє подібно до оператора групування в JavaScript-виразах, даючи змогу використовувати підпатерн як єдиний атом.
Групи захоплення нумеруються за порядком їхніх стартових дужок. Перша група захоплення отримує номер 1
, друга – 2
, і так далі. Іменовані групи захоплення також є групами захоплення та нумеруються разом з іншими (безіменними) групами захоплення. Інформацію про збіг з групою захоплення можна отримати за допомогою:
- Поверненого значення (котре є масивом) з методу
RegExp.prototype.exec()
,String.prototype.match()
абоString.prototype.matchAll()
- Параметрів
pN
функції зворотного викликуreplacement
методівString.prototype.replace()
іString.prototype.replaceAll()
- Зворотних посилань у межах того самого патерну
Примітка: Навіть у результівному масиві методу
exec()
групи захоплення доступні за числами1
,2
тощо, адже елемент0
– це ввесь збіг.\0
– це не зворотне посилання, а послідовність екранування для символу NUL.
Групи захоплення у вихідному коді регулярного виразу відповідають своїм результатам один до одного. Якщо група захоплення не отримала збігу (наприклад, коли вона належить до варіанту диз'юнкції, що не отримав збігу), то відповідним результатом є undefined
.
/(ab)|(cd)/.exec("cd"); // ['cd', undefined, 'cd']
Групи захоплення можуть бути квантовані. У такому випадку інформація про збіг, що відповідає такій групі, – це останній збіг групи.
/([ab])+/.exec("abc"); // ['ab', 'b']; через те, що "b" стоїть після "a", цей результат відкидає попередній
Групи захоплення можуть вживатися у твердженнях визирання й озирання. У зв'язку з тим, що твердження озирання шукають збіг зі своїми атомами позаду справа наліво, то остаточний збіг, що відповідає такій групі, це той, що стоїть з лівого боку рядка. А проте, індекси груп збігів все одно відповідатимуть їхнім відносним розташуванням у вихідному коді регулярного виразу.
/c(?=(ab))/.exec("cab"); // ['c', 'ab']
/(?<=(a)(b))c/.exec("abc"); // ['c', 'a', 'b']
/(?<=([ab])+)c/.exec("abc"); // ['c', 'a']; тому що "a" помічено озиранням після того, як озиранням помічено "b"
Групи захоплення можуть мати вкладеність, у випадку чого зовнішня група нумерується першою, потім – внутрішня група, тому що нумерація відповідає стартовим дужкам. Якщо вкладена група повторюється за допомогою квантора, то кожного разу, коли з нею трапляється збіг, результати підгруп перезаписуються, іноді – значенням undefined
.
/((a+)?(b+)?(c))*/.exec("aacbbbcac"); // ['aacbbbcac', 'ac', 'a', undefined, 'c']
У прикладі вище зовнішня група збігається тричі:
- Збігається з
"aac"
, з підгрупами"aa"
,undefined
і"c"
. - Збігається з
"bbbc"
, з підгрупамиundefined
,"bbb"
і"c"
. - Збігається з
"ac"
, з підгрупами"a"
,undefined
і"c"
.
Результат "bbb"
з другого збігу – не зберігається, тому що третій збіг відкидає його своїм значенням undefined
.
Початковий та кінцевий індекси кожної групи захоплення в вихідному рядку можна отримати за допомогою позначки d
. Це створює додаткову властивість indices
у масиві, поверненому з exec()
.
Іще можна задати назву групи захоплення, що допомагає уникнути пасток, пов'язаних із позиціями груп та індексами. Докладніше про це – читайте Іменовані групи захоплення.
Дужки в різних записах регулярних виразів мають інші значення. Наприклад, також вони охоплюють твердження визирання й озирання. Через те, що всі такі записи починаються з ?
, а ?
- це квантор, котрий зазвичай не стоїть зразу після (
, це не призводить до неоднозначностей.
Приклади
Пошук дати
Наступний приклад шукає дату в форматі YYYY-MM-DD
:
function parseDate(input) {
const parts = /^(\d{4})-(\d{2})-(\d{2})$/.exec(input);
if (!parts) {
return null;
}
return parts.map((p) => parseInt(p, 10));
}
parseDate("2019-01-01"); // [2019, 1, 1]
parseDate("2019-06-19"); // [2019, 6, 19]
Парування лапок
Наступна функція шукає в рядку патерни title='xxx'
і title="xxx"
. Аби пересвідчитися, що лапки збігаються, використовується зворотне посилання, аби звернутися до першої лапки. Звертання до другої групи захоплення ([2]
) повертає рядок між лапками, що збігаються:
function parseTitle(metastring) {
return metastring.match(/title=(["'])(.*?)\1/)[2];
}
parseTitle('title="foo"'); // 'foo'
parseTitle("title='foo' lang='en'"); // 'foo'
parseTitle('title="Named capturing groups\' advantages"'); // "Named capturing groups' advantages"