JavaScript | Квантификатор {} фигурные скобки в регулярных выражениях

JavaScript | Квантификатор {} фигурные скобки в регулярных выражениях

 

В этой публикации мы рассмотрим такой вид префикса квантификатора (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]

Скриншот выводов:

Идентичное сопоставление обычной дизъюнкции и префикса квантификатора с фигурными скобками и одним целым числом - JavaScript
Идентичное сопоставление обычной дизъюнкции и префикса квантификатора с фигурными скобками и одним целым числом — JavaScript

Оба варианта записи дают нам идентичный результат. Но мы «вешали» префикс квантификатора на один символ. А как он будет работать с последовательностью символов?

 

Пример. Есть другая строка:

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. Утверждено: xeye.
         2. Пусть s будет Списком, элементы которого являются символами Input с индексами от xe (включительно) до ye (исключая).
      vi. Иначе,
         1. Утверждено: направление direction равен -1.
         2. Утверждено: yexe.
         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» и заменена.

Эквивалент бесконечности повторения одного символа подряд - JavaScript
Эквивалент бесконечности повторения одного символа подряд — JavaScript

 

Префикс Квантификатора — { 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» остаются на своих местах т.к. метод замены уже отработал с регулярным выражением.

Замена от двух до четырёх повторений символа по строке единожды слева-направо - JavaScript
Замена от двух до четырёх повторений символа по строке единожды слева-направо — JavaScript

 

Другой пример:

"ef-X-eeff-X-eeefff-X-eeeeffff".replace(/f{3,4}/g,"")
"ef-X-eeff-X-eee-X-eeee"

В этом примере диапазон повторений символа «f» от 3 до 4 раз подряд. Шаблон регулярного выражения сопоставляется ГЛОБАЛЬНО по всей строке т.к. установлен флаг «g» для регулярного выражения. После первого найденного сопоставления будет продолжено по остаткам строки.

Замена трёх-четырёх повторений символа глобально по строке - JavaScript
Замена трёх-четырёх повторений символа глобально по строке — JavaScript

Пример работы префикса квантификатора с дизъюнкцией из двух символов:

"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)