Лучшие результаты сопоставления с помощью String.prototype.matchAll()

Джо Медли
Joe Medley

В Chrome 73 представлен метод String.prototype.matchAll() . Он ведет себя аналогично match() , но возвращает итератор со всеми совпадениями регулярных выражений в глобальном или прикрепленном регулярном выражении. Это предлагает простой способ перебора совпадений, особенно когда вам нужен доступ к группам захвата.

Что не так с match()?

Короткий ответ: ничего, если только вы не пытаетесь вернуть глобальные совпадения с группами захвата. Вот вам головоломка по программированию. Рассмотрим следующий код:

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const results = string.match(regex);
console.log(results);
// → ['test1', 'test2']

Запустите это в консоли и обратите внимание, что он возвращает массив, содержащий строки 'test1' и 'test2' . Если я удалю флаг g из регулярного выражения, я получу все мои группы захвата, но получу только первое совпадение. Это выглядит так:

['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined]

Эта строка содержит второе возможное совпадение, начинающееся с 'test2' но у меня его нет. Теперь вот загадка: как мне получить все группы захвата для каждого совпадения? Объяснение предложения String.prototype.matchAll() показывает два возможных подхода. Я не буду их описывать, потому что, надеюсь, они вам больше не понадобятся.

String.prototype.matchAll()

Как будут выглядеть примеры пояснений с помощью matchAll() ? Взгляни.

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const matches = string.matchAll(regex);
for (const match of matches) {
  console.log(match);
}

По этому поводу следует отметить несколько вещей. В отличие от match() , который возвращает массив при глобальном поиске, matchAll() возвращает итератор, который прекрасно работает с циклами for...of . Итератор создает массив для каждого совпадения, включая группы захвата с некоторыми дополнениями. Если вы распечатаете их на консоли, они будут выглядеть так:

['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', groups: undefined]
['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]

Вы можете заметить, что значение каждого совпадения представляет собой массив точно такого же формата, который возвращается функцией match() для неглобальных регулярных выражений.

Бонусный материал

Это в основном для людей, которые плохо знакомы с регулярными выражениями или не являются в этом экспертами. Возможно, вы заметили, что результаты match() и matchAll() (для каждой итерации) представляют собой массивы с некоторыми дополнительными именованными свойствами. Готовя эту статью, я заметил, что у этих свойств есть некоторые недостатки документации на MDN (которые я исправил ). Вот краткое описание.

index
Индекс первого результата в исходной строке. В приведенном выше примере test2 начинается с позиции 5, следовательно, index имеет значение 5.
input
Полная строка, для которой выполнялся matchAll() . В моем примере это было 'test1test2' .
groups
Содержит результаты любых именованных групп захвата, указанных в регулярном выражении.

Заключение

Если я что-то пропустил, пожалуйста, дайте мне знать в комментариях ниже. Подробнее о последних изменениях в JavaScript можно прочитать в предыдущих обновлениях или на сайте V8 .