В этой публикации мы рассмотрим такой вид префикса квантификатора (QuantifierPrefix) для шаблона (Pattern) регулярного выражения (RegExp), который обозначается фигурными скобками. В стандарте ECMAScript описаны три способа производства префикса квантификатора с фигурными скобками:
Производство префикса QuantifierPrefix :: { DecimalDigits } оценивается следующим образом:
1. Пусть i будет MV (mathematical value) из Десятичных Цифр (см. 12.8.3). 2. Верните два результата i и i.
Производство префикса QuantifierPrefix :: { DecimalDigits , } оценивается следующим образом:
1. Пусть i будет MV (mathematical value) из Десятичных Цифр (см. 12.8.3). 2. Верните два результата i и +∞.
Производство префикса QuantifierPrefix :: { DecimalDigits , DecimalDigits } оценивается следующим образом:
1. Пусть i будет MV (mathematical value) первой из десятичных цифр DecimalDigits. 2. Пусть j будет MV (mathematical value) второй из десятичных цифр DecimalDigits. 3. Верните два результата i и j.
Рассмотрим их отдельно.
Префикс Квантификатора — { DecimalDigits }
Видео
Этот синтаксис предполагает заполнение фигурных скобок одним целым числом. Как это работает? Целое число указывает на количество повторений символа в последовательности по которому будет происходить сопоставление.
Есть строка:
var stroka = "eeefffiiimmm"
Мы хотим сопоставить строку по шаблону, который найдёт два подряд символа «f«. Мы бы могли записать это так:
/ff/
Префикс квантификатора фигурных скобок с одним целым числом даёт нам возможность указать какое количество раз будет сопоставлен символ в шаблоне регулярного выражения. То есть мы теперь можем записать так:
/f{2}/
Пример из консоли браузера:
/ff/.exec(stroka) ["ff", index: 3, input: "eeefffiiimmm", groups: undefined]
/f{2}/.exec(stroka) ["ff", index: 3, input: "eeefffiiimmm", groups: undefined]
Скриншот выводов:
Оба варианта записи дают нам идентичный результат. Но мы «вешали» префикс квантификатора на один символ. А как он будет работать с последовательностью символов?
Пример. Есть другая строка:
var stroka = "eeefifififimmm"
Мы хотим сопоставить строку по шаблону, который найдёт три подряд последовательности символов «fi«. Мы бы могли записать это так в классической дизъюнкции:
/fififi/
С префиксом, по логике, регулярное выражение должно выглядеть так:
/fi{3}/
Пример из консоли браузера:
/fififi/.exec(stroka) ["fififi", index: 3, input: "eeefifififimmm", groups: undefined]
/fi{3}/.exec(stroka) null
Но мы получим null
, потому что префикс квантификатора сработает только по соседнему левому одному символу «i«. В результате шаблон примет вид «fiii«. В нашей строке такой последовательности символов нет, а значит метод exec()
вернёт нам null
.
Чтобы мы могли решить задачу так, как запланировали, нам нужно обернуть последовательность символов «fi» в круглые скобки:
/(fi){3}/
После этого мы получим нужный нам результат:
var stroka = "eeefifififimmm" stroka.replace(/(fi){3}/,"") "eeefimmm"
Мы воспользовались Атомом (Atom) для шаблона регулярного выражения. Его производство выглядит описано ниже.
Производство Atom :: ( GroupSpecifier Disjunction ) оценивается следующим образом:
1. Оцените Дизъюнкцию (Disjunction) с аргументом direction, чтобы получить Сопоставитель Matcher m. 2. Пусть parenIndex будет числом скобок с левым захватом во всем регулярном выражении, которое встречается слева от этого Атома Atom. Это общее количество узлов синтаксического анализа Атома Atom :: ( GroupSpecifier Disjunction ), предшествующих или включающих этот Атом Atom. 3. Верните новый Сопоставитель Matcher с параметрами (x, c), который фиксирует направление direction, m и parenIndex и при вызове выполняет следующие шаги: а. Утверждено: x - это Состояние (State). b. Утверждено: c - это Продолжение (Continuation). c. Пусть d будет новым Продолжением с параметрами (y), которое захватывает x, c, direction и parenIndex и при вызове выполняет следующие шаги: i. Утверждено: y - это Состояние (State). ii. Пусть cap будет копией Списка y из captures. iii. Пусть xe будет endIndex для x. iv. Пусть ye будет endIndex из у. v. Если direction = 1, тогда 1. Утверждено: xe ≤ ye. 2. Пусть s будет Списком, элементы которого являются символами Input с индексами от xe (включительно) до ye (исключая). vi. Иначе, 1. Утверждено: направление direction равен -1. 2. Утверждено: ye ≤ xe. 3. Пусть s будет Списком, элементы которого являются символами Input с индексами от ye (включительно) до xe (исключая). vii. Установите cap[parenIndex + 1] в s. viii. Пусть z будет Состоянием (ye, cap). ix. Верните c(z). d. Верните m(x, d).
GroupSpecifier у нас пустой, а Дизъюнкция(Disjunction) содержит последовательность символов «fi«. Только в сочетании «(fi){3}» последовательность символов «fi» будет умножена на 3 и «преобразована» в нужную нам «fififi«.
Префикс Квантификатора — { DecimalDigits , }
Видео
Этот синтаксис предполагает заполнение фигурных скобок одним целым числом и запятой. Как это работает? Первое целое число указывает на минимальное количество повторений символа в последовательности. Запятая и скобка обозначает бесконечное количество повторений символа в последовательности. Сопоставляется диапазон.
Есть строка:
var stroka = "eeefffiiimmm"
Есть регулярное выражение вида:
/f{1,}/
Результат сопоставления найдёт первую возможную последовательность до бесконечности повторения символа «f«. Проверим на замене методом replace()
stroka.replace(/f{1,}/,"") "eeeiiimmm"
Будет найдена самая длинная последовательность символов «f» и заменена.
Префикс Квантификатора — { DecimalDigits , DecimalDigits }
Видео
Этот синтаксис предполагает заполнение фигурных скобок одним целым числом одной запятой и одним целым числом. Как это работает? Первое целое число указывает на минимальное количество повторений символа в последовательности. Второе целое число указывает на максимальное количество повторений символа в последовательности. Сопоставляется диапазон.
Есть строка:
var stroka = "eeefffiiimmm"
Есть регулярное выражение вида:
/f{1,3}/
Такая запись найдёт те места в строке слева-направо, где будут последовательно расположены один или три символа «f«.
stroka.replace(/f{1,3}/,"") "eeeiiimmm"
В итоге мы получим строку без символов «f«, потому что в строке символ встречается три раза, а это подпадает под условие.
Другой пример:
"ef-X-eeff-X-eeefff-X-eeeeffff".replace(/f{2,4}/,"") "ef-X-ee-X-eeefff-X-eeeeffff"
Сопоставление сработает один раз т. к. нет никаких флагов. Слева направо первым встречается один символ «f«. Он не попадает под условие префикса квантификатора т.к. символ один, а не два.
Вторым встречается два подряд символа «f«. Это попадает под условие. Происходит замена. Остальные последовательности с символом «f» остаются на своих местах т.к. метод замены уже отработал с регулярным выражением.
Другой пример:
"ef-X-eeff-X-eeefff-X-eeeeffff".replace(/f{3,4}/g,"") "ef-X-eeff-X-eee-X-eeee"
В этом примере диапазон повторений символа «f» от 3 до 4 раз подряд. Шаблон регулярного выражения сопоставляется ГЛОБАЛЬНО по всей строке т.к. установлен флаг «g» для регулярного выражения. После первого найденного сопоставления будет продолжено по остаткам строки.
Пример работы префикса квантификатора с дизъюнкцией из двух символов:
"efi-X-eefifi-X-eeefififi-X-eeeefifififi".replace(/(fi){3,4}/,"") "efi-X-eefifi-X-eee-X-eeeefifififi" "efi-X-eefifi-X-eeefififi-X-eeeefifififi".replace(/(fi){3,4}/g,"") "efi-X-eefifi-X-eee-X-eeee"
Скрин из браузера
Информационные ссылки
JavaScript | Квантификаторы *(звёздочка), +(плюс), ?(вопрос)
ECMAScript | Квантификатор (Quantifier) | Регулярные выражения (Regular Expression)
JavaScript | Как экранировать круглую скобку в регулярных выражениях?
Стандарт ECMAScript — Раздел «22.2.2.3 Disjunction» — https://tc39.es/ecma262/#sec-disjunction
ECMAScript | Атом (Atom) | Регулярные выражения (Regular Expression)