Regex Essentials
В одной фразе: RegExp с флагом g — stateful объект: свойство lastIndex меняется между вызовами, что приводит к трудноуловимым багам при переиспользовании. На собесе проверяют named capture groups, lookahead/lookbehind, флаги и ловушку с /g в цикле.
// Named capture groups (ES2018): читаемее и стабильнее numberedconst 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 regexconst re = /\d+/g;re.test('abc123'); // true, re.lastIndex = 6re.test('456def'); // false! поиск начат с позиции 6 — не нашлиre.test('789'); // true, сброс lastIndex (не нашли с 6, начали с 0)
// ✅ String.matchAll — возвращает итерируемое, не мутирует re.lastIndexconst 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 — предпочтительный способ получить все совпадения с группами.