Перейти к содержимому

Regex Essentials

В одной фразе: RegExp с флагом g — stateful объект: свойство lastIndex меняется между вызовами, что приводит к трудноуловимым багам при переиспользовании. На собесе проверяют named capture groups, lookahead/lookbehind, флаги и ловушку с /g в цикле.

// Named capture groups (ES2018): читаемее и стабильнее numbered
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = '2024-01-15'.match(dateRe);
const { year, month, day } = m.groups; // year='2024', month='01', day='15'
// replace с named groups через $<name>
'2024-01-15'.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
'$<day>/$<month>/$<year>'
); // '15/01/2024'
// Lookahead / Lookbehind: проверка контекста без захвата
// Lookahead (?=...) — за совпадением следует паттерн
'100px 200em 300px'.match(/\d+(?=px)/g); // ['100', '300']
// Lookbehind ES2018 (?<=...) — перед совпадением стоит паттерн
'$100 €200 $300'.match(/(?<=$)\d+/g); // ['100', '300']
// Negative lookahead (?!...) и lookbehind (?<!...)
'100px 200em'.match(/\d+(?!px)(?<!\d)em/g); // ищем число перед em, но не px
// Ловушка: /g флаг и lastIndex — stateful regex
const re = /\d+/g;
re.test('abc123'); // true, re.lastIndex = 6
re.test('456def'); // false! поиск начат с позиции 6 — не нашли
re.test('789'); // true, сброс lastIndex (не нашли с 6, начали с 0)
// ✅ String.matchAll — возвращает итерируемое, не мутирует re.lastIndex
const str = 'abc123def456';
const matches = [...str.matchAll(/\d+/g)];
matches.map(m => m[0]); // ['123', '456']
// Каждый match содержит: m[0]=вся строка, m.index, m.groups, m.input

Итог: Флаг g делает regex stateful через lastIndex. String.matchAll — предпочтительный способ получить все совпадения с группами.