String.prototype.matchAll()

Метод matchAll() (шукати всі збіги) значень String повертає ітератор з усіма результатами зіставлення свого рядка з регулярним виразом, в тому числі групи захоплення.

Спробуйте його в дії

Синтаксис

matchAll(regexp)

Параметри

regexp

Об'єкт регулярного виразу, або ж будь-який об'єкт, що має метод Symbol.matchAll.

Якщо regexp не є об'єктом RegExp і не має методу Symbol.matchAll, то він неявно перетворюється на RegExp за допомогою new RegExp(regexp, 'g').

Якщо regexp є регулярним виразом, то цей регулярний вираз повинен мати позначку глобальності (g), а інакше – викидається TypeError.

Повернене значення

Ітерований об'єкт-ітератор (непридатний до повторного перебирання) зі збігами, або порожній ітератор, якщо жодного збігу не знайдено. Кожне значення, видане таким ітератором, є масивом з такою ж структурою, як повернене значення методу RegExp.prototype.exec().

Винятки

TypeError

Викидається, коли regexp є регулярним виразом, але не має позначки глобальності (g) (тобто його властивість flags не містить "g").

Опис

Реалізація String.prototype.matchAll сама по собі є дуже простою: цей метод просто викликає метод Symbol.matchAll свого аргументу з вихідним рядком як першим параметром (коли не рахувати додаткової валідації вихідних даних на предмет того, що регулярний вираз є глобальним). Фактична реалізація надходить із RegExp.prototype[@@matchAll].

Приклади

Методи Regexp.prototype.exec() і matchAll()

Без matchAll() отримувати всі збіги можна за допомогою викликів regexp.exec() (і регулярних виразів з позначкою g) у циклі:

const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
let match;

while ((match = regexp.exec(str)) !== null) {
  console.log(
    `Знайдено слово ${match[0]}, початок=${match.index}, закінчення=${regexp.lastIndex}.`,
  );
}
// Знайдено слово football, початок=6, закінчення=14.
// Знайдено слово foosball, початок=16, закінчення=24.

За наявності методу matchAll є можливість уникати циклу while і використання методу exec із g. Це можливо завдяки тому, що повертається ітератор, який можна використовувати зі зручнішими конструкціями – for...of, розгортанням масиву і Array.from():

const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(
    `Знайдено слово ${match[0]}, початок=${match.index}, закінчення=${
      match.index + match[0].length
    }.`,
  );
}
// Знайдено слово football, початок=6, закінчення=14.
// Знайдено слово foosball, початок=16, закінчення=24.

// ітератор зі збігами вичерпується після перебирання у for...of
// Новий виклик matchAll створить новий ітератор
Array.from(str.matchAll(regexp), (m) => m[0]);
// [ "football", "foosball" ]

Якщо прапорець g опущено, метод matchAll викине виняток.

const regexp = /[a-c]/;
const str = "abc";
str.matchAll(regexp);
// TypeError

Метод matchAll для своїх потреб створює клон глобального об'єкта RegExp. Тому, на відміну від використання методу regexp.exec(), властивість lastIndex об'єкта RegExp не змінюється під час сканування рядка.

const regexp = /[a-c]/g;
regexp.lastIndex = 1;
const str = "abc";
Array.from(str.matchAll(regexp), (m) => `${regexp.lastIndex} ${m[0]}`);
// [ "1 b", "1 c" ]

Проте це означає, що на відміну від використання regexp.exec() у циклі, не можна змінювати lastIndex для перемотування регулярного виразу вперед або назад.

Кращий доступ до груп захоплення (ніж у String.prototype.match())

Іншою привабливою причиною використати matchAll є покращений доступ до груп захоплення.

Під час застосування match() з прапорцем глобального пошуку g групи захоплення ігноруються:

const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

str.match(regexp); // ['test1', 'test2']

За допомогою matchAll можна легко отримати доступ до груп:

const array = [...str.matchAll(regexp)];

array[0];
// ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4]
array[1];
// ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4]

Застосування matchAll() вкупі з об'єктом, що не є RegExp, але має реалізацію @@matchAll

Якщо об'єкт має метод Symbol.matchAll, то він може використовуватися як власний шукач збігів. Повернене значення Symbol.matchAll стає поверненим значенням matchAll().

const str = "Гм, це цікаво.";
str.matchAll({
  [Symbol.matchAll](str) {
    return [["Так, це цікаво."]];
  },
}); // returns [["Yes, it's interesting."]]

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
matchAll
Chrome Full support 73
Edge Full support 79
Firefox Full support 67
Internet Explorer No support No
Opera Full support 60
Safari Full support 13
WebView Android Full support 73
Chrome Android Full support 73
Firefox for Android Full support 67
Opera Android Full support 52
Safari on iOS Full support 13
Samsung Internet Full support 11.0
Deno Full support 1.0
Node.js Full support 12.0.0

Дивіться також