repattern Спецификация 1.0.0-beta.0

Спецификация встраиваемого DSL для создания регулярных выражений в JavaScript на основе декларативных схем.

Языки: Английский

Участие: GitHub teplostanski/repattern-spec (создать issue, открытые issues)

Аннотация

Спецификация repattern — встраиваемого DSL для создания регулярных выражений в JavaScript на основе декларативных схем типа Scheme, которые преобразуются в объекты RegExp.

Схемы представляют собой человекочитаемый формат описания шаблонов, альтернативный написанию регулярных выражений вручную.

Note

Для эффективного использования данной спецификации рекомендуется понимать термины и принципы работы регулярных выражений, так как схемы описывают те же концепции в декларативном формате.

Содержание

  1. Термины
    1. Схема
    2. Атом
    3. Секвенсор
    4. Атом‑секвенсор
    5. Объект параметров params
  2. Типы
    1. Scheme
    2. Atom
    3. AtomSequencer
    4. Params
  3. Атомы-секвенсоры
    1. Квантификаторы
      1. repeat
      2. zeroOrMore
      3. maybe
    2. Группа
      1. grouped
    3. Альтернация
      1. anyOf
  4. Атомы
    1. Якоря
      1. lineStart
      2. lineEnd
    2. Литералы и специальные символы
      1. exactly
      2. anyChar
      3. tab
      4. lineFeed
      5. carriageReturn
    3. Символьные наборы
      1. charIn
      2. charNotIn
    4. Ссылки на группы
      1. referenceTo
    5. Unicode свойства
      1. unicodeProps
    6. Символьные классы
      1. digit
      2. word
      3. whitespace
      4. boundary

1. Термины

1.1. Схема

Схема — это массив (секвенсор) объектов (атомов), описывающий структуру регулярного выражения в декларативном формате. Каждый элемент схемы (атом) представляет один логический шаг шаблона.

Простой пример:

const scheme = [
  { lineStart: true },
  { zeroOrMore: [{ charIn: 'a-z' }] },
  { lineEnd: true },
];
// Результат: /^[a-z]*$/

Пример: валидация email адреса

Регулярное выражение:

/^(?:[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-])+@[a-zA-Z0-9](?:(?:[a-zA-Z0-9-]){0,61}[a-zA-Z0-9])?
(?:\.[a-zA-Z0-9](?:(?:[a-zA-Z0-9-]){0,61}[a-zA-Z0-9])?)+$/

Данное регулярное выражение проверяет корректность email адреса согласно стандарту RFC 5322.

Схема, описывающая это регулярное выражение:

const scheme = [
  { lineStart: true }, // ^
  {
    repeat: [
      // (?: ... )+
      { charIn: "a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-" }, // [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]
    ],
  },
  { exactly: '@' }, // @
  { charIn: 'a-zA-Z0-9' }, // [a-zA-Z0-9]
  {
    maybe: [
      // (?: ... )?
      {
        repeat: [
          // (?: ... ){0,61}
          { charIn: 'a-zA-Z0-9-' }, // [a-zA-Z0-9-]
          { params: { times: [0, 61] } },
        ],
      },
      { charIn: 'a-zA-Z0-9' }, // [a-zA-Z0-9]
    ],
  },
  {
    repeat: [
      // (?: ... )+
      { exactly: '.' }, // .
      { charIn: 'a-zA-Z0-9' }, // [a-zA-Z0-9]
      {
        maybe: [
          // (?: ... )?
          {
            repeat: [
              // (?: ... ){0,61}
              { charIn: 'a-zA-Z0-9-' }, // [a-zA-Z0-9-]
              { params: { times: [0, 61] } },
            ],
          },
          { charIn: 'a-zA-Z0-9' }, // [a-zA-Z0-9]
        ],
      },
    ],
  },
  { lineEnd: true }, // $
];

1.2. Атом

Атом — это минимальная единица схемы, описывающая один логический шаг шаблона (якорь, символьный класс, квантифицированную последовательность, альтернацию и т.п.).

Атом представляет собой объект с ровно одним ключом, который определяет тип шага. Значением этого ключа может быть только:

  • строка;
  • число или массив из двух чисел (только для параметра times, см. Объект параметров params);
  • булево значение;
  • массив атомов (секвенсор) или, в случае anyOf, массив анонимных секвенсоров.

Значением атома не может быть другой атом или произвольный объект.

Любой объект, встречающийся в схеме, трактуется как атом, кроме специального объекта параметров params, который не считается атомом и не описывает отдельный шаг шаблона (см. Объект параметров params).

Атомы:

1.3. Секвенсор

Секвенсор — это массив атомов, объединяющий несколько подшаблонов в последовательность. Порядок атомов в секвенсоре соответствует их порядку в итоговом регулярном выражении.

Типы секвенсоров В схеме существует три типа секвенсоров, различающихся по контексту и допустимому содержимому:

  • Корневой секвенсор — верхнеуровневый массив схемы. Содержит только атомы.

  • Атом‑секвенсор — атом, значением которого является секвенсор (см. Атом‑секвенсор).

  • Анонимный секвенсор — секвенсор без имени, встречающийся только внутри атома‑секвенсора anyOf. Используется для описания альтернативных ветвей и может содержать только атомы.

1.4. Атом‑секвенсор

Атом‑секвенсор — это атом, значением которого является секвенсор (массив атомов) или, для anyOf, массив секвенсоров. Описывает последовательность подшаблонов: вложенные атомы интерпретируются в порядке следования в массиве и соответствуют конкатенации подшаблонов внутри одной группирующей конструкции.

Атом‑секвенсор всегда выступает как обёртка над подшаблонами, эквивалентная одной из групп регулярного выражения:

  • не захватывающая (?: … )
  • захватывающая ( … )
  • именованная (?<name> … )

По умолчанию атом‑секвенсор создаёт не захватывающую группу (?: … ) в качестве обёртки (кроме grouped). Тип обёртки можно изменить с помощью параметра group в объекте параметров params.

Атомы‑секвенсоры:

1.5. Объект параметров params

Объект параметров params — это служебный элемент, предназначенный для задания параметров атома‑секвенсора. Он не считается атомом схемы, не участвует в последовательности подшаблонов и не влияет на порядок исполнения вложенных атомов. Объект params должен находиться в конце массива атома‑секвенсора и интерпретируется как метаданные для родительского атома‑секвенсора.

Параметры

times

Задаёт точное количество повторений или диапазон.

Применяется только к квантификатору repeat.

times?: number | [number] | [number, number];
ЗначениеЭквивалентОписание
n{n}ровно n повторений
[min]{min,}от min до бесконечности
[min, max]{min,max}диапазон повторений

Если параметр times не указан, используется квантификатор + (повторить 1 раз или больше).

lazy

Флаг ленивого квантификатора.

Значение true — делает квантификатор ленивым (*?, {n,}?), значение false отключает флаг. Применяется ко всем квантификаторам: repeat, zeroOrMore, maybe.

lazy?: boolean;

group

Определяет тип группирующей конструкции:

  • false: не захватывающая группа (?: … )
  • true: захватывающая группа ( … )
  • "<name>": именованная группа (?<name> … )
group?: boolean | string;

optionally

Флаг, делающий группу необязательной.

Применяется только к альтернации anyOf.

optionally?: boolean;

Контекст использования

Объект params может находиться только внутри атомов‑секвенсоров.

Таблица соотношений параметров и атомов-секвенсоров:

ПараметрАтом-секвенсор
timesrepeat
lazyrepeat, zeroOrMore, maybe
grouprepeat, zeroOrMore, maybe, grouped, anyOf
optionallyanyOf

2. Типы

Данный раздел описывает типы TypeScript для работы со схемами.

2.1. Scheme

Тип схемы — корневой секвенсор, содержащий только атомы.

type Scheme = Atom[];

2.2. Atom

Атом — минимальная единица схемы. Объединение всех типов атомов.

type Atom = BooleanAtom | StringAtom | ReferenceToAtom | AtomSequencer;

type BooleanAtom =
  | { lineStart: boolean }
  | { lineEnd: boolean }
  | { digit: boolean }
  | { word: boolean }
  | { whitespace: boolean }
  | { boundary: boolean }
  | { anyChar: boolean }
  | { tab: boolean }
  | { lineFeed: boolean }
  | { carriageReturn: boolean };

type StringAtom =
  | { exactly: string }
  | { charIn: string }
  | { charNotIn: string }
  | { unicodeProps: string };

type ReferenceToAtom = { referenceTo: number | string };

2.3. AtomSequencer

Атомы‑секвенсоры, принимающие секвенсор (или, для anyOf, массив секвенсоров) с соответствующими типами параметров.

type AtomSequencer =
  | { repeat: RepeatSequence }
  | { zeroOrMore: ZeroOrMoreSequence }
  | { maybe: MaybeSequence }
  | { grouped: GroupedSequence }
  | { anyOf: AnyOfSequence };

type RepeatSequence = [...Atom[], { params: RepeatParams }?] | Atom[];

type ZeroOrMoreSequence = [...Atom[], { params: ZeroOrMoreParams }?] | Atom[];

type MaybeSequence = [...Atom[], { params: MaybeParams }?] | Atom[];

type GroupedSequence = [...Atom[], { params: GroupedParams }?] | Atom[];

type AnyOfSequence = [...Atom[][], { params: AnyOfParams }?] | Atom[][];

2.4. Params

Типы параметров для атомов‑секвенсоров. Каждый атом‑секвенсор имеет свой набор допустимых параметров.

type Params =
  | RepeatParams
  | ZeroOrMoreParams
  | MaybeParams
  | GroupedParams
  | AnyOfParams;

type RepeatParams = {
  times?: number | [number] | [number, number];
  lazy?: boolean;
  group?: boolean | string;
};

type ZeroOrMoreParams = {
  lazy?: boolean;
  group?: boolean | string;
};

type MaybeParams = {
  lazy?: boolean;
  group?: boolean | string;
};

type GroupedParams = {
  group?: boolean | string;
};

type AnyOfParams = {
  group?: boolean | string;
  optionally?: boolean;
};

3. Атомы-секвенсоры

3.1. Квантификаторы

3.1.1 repeat

  • Тип: AtomSequencer
  • Эквивалент: {n}, {min,max}, {min,}, +

repeat — Создаёт группу с квантификатором повторения. Объединяет подшаблоны и позволяет повторять их с заданной кратностью.

Поддерживаемые параметры

Объект params может содержать (см. Объект параметров params):

  • times — без параметра эквивалентно + (1 раз или больше);
  • lazy — по умолчанию false;
  • group — по умолчанию false (не захватывающая группа (?: … )).

Примеры

const scheme = [
  { repeat: [{ charIn: 'a-z' }, { params: { times: [0, 3], lazy: true } }] },
];
// Результат: /(?:[a-z]){0,3}?/

const scheme = [
  { repeat: [{ exactly: 'foo' }, { params: { group: 'word' } }] },
];
// Результат: /(?<word>foo)+/

3.1.2. zeroOrMore

zeroOrMore — Создаёт группу с квантификатором *. Повторяет подшаблон ноль или более раз.

Поддерживаемые параметры

Объект params может содержать (см. Объект параметров params):

  • lazy — по умолчанию false;
  • group — по умолчанию false (не захватывающая группа (?: … )).

Примеры

const scheme = [{ zeroOrMore: [{ exactly: 'foo' }] }];
// Результат: /(?:foo)*/

const scheme = [
  {
    zeroOrMore: [
      { charIn: 'a-z' },
      { params: { group: 'letters', lazy: true } },
    ],
  },
];
// Результат: /(?<letters>[a-z]*?)/

3.1.3. maybe

maybe — Создаёт группу с квантификатором ? (повторить подшаблон ноль или один раз). Делает подшаблон необязательным.

Поддерживаемые параметры

Объект params может содержать (см. Объект параметров params):

  • lazy — по умолчанию false;
  • group — по умолчанию false (не захватывающая группа (?: … )).

Примеры

const scheme = [{ maybe: [{ exactly: 'foo' }] }];
// Результат: /(?:foo)?/

const scheme = [
  { maybe: [{ charIn: 'A-Z' }, { params: { group: 'opt', lazy: true } }] },
];
// Результат: /(?<opt>[A-Z])??/

Note

Для anyOf с глубокой вложенностью ветвей альтернатив рекомендуется использовать параметр optionally вместо оборачивания в maybe, чтобы избежать излишней вложенности.


3.2. Группа

3.2.1. grouped

  • Тип: AtomSequencer
  • Эквивалент: (...), (?:...), (?<name>...)

grouped — Создаёт группирующую конструкцию. Объединяет несколько подшаблонов в одну логическую группу.

Поддерживаемые параметры

Объект params может содержать (см. Объект параметров params):

  • group — по умолчанию true (захватывающая группа ( … )).

Примеры

const scheme = [{ grouped: [{ exactly: 'foo' }, { charIn: 'A-Z' }] }];
// Результат: /(foo[A-Z])/

const scheme = [
  { grouped: [{ exactly: 'bar' }, { params: { group: false } }] },
];
// Результат: /(?:bar)/

const scheme = [
  { grouped: [{ exactly: 'buzz' }, { params: { group: 'word' } }] },
];
// Результат: /(?<word>buzz)/

3.3. Альтернация

3.3.1. anyOf

anyOf — Создаёт альтернацию (оператор выбора). Объединяет несколько ветвей альтернативы, из которых должна совпасть хотя бы одна.

Структура

Значением ключа anyOf является массив анонимных секвенсоров (ветвей альтернативы):

{
  anyOf: [
    [ /* ветвь 1 */ ],
    [ /* ветвь 2 */ ],
    ...
  ]
}

Поддерживаемые параметры

Объект params может содержать (см. Объект параметров params):

  • group — по умолчанию false (не захватывающая группа (?: … ));
  • optionally — по умолчанию false.

Note

Для создания необязательной альтернации используйте параметр optionally вместо оборачивания anyOf в maybe, чтобы избежать излишней вложенности.

Примеры

const scheme = [
  {
    anyOf: [
      [{ charIn: '01' }, { digit: true }], // ветвь 1
      [{ exactly: '2' }, { charIn: '0-3' }], // ветвь 2
      { params: { group: 'hours' } },
    ],
  },
  { exactly: ':' },
  {
    grouped: [
      { charIn: '0-5' },
      { digit: true },
      { params: { group: 'minutes' } },
    ],
  },
];
// Результат: /(?<hours>[01]\d|2[0-3]):(?<minutes>[0-5]\d)/

const str = '23:59 25:99 1:2';
const re = /(?<hours>[01]\d|2[0-3]):(?<minutes>[0-5]\d)/;
const result = str.match(re);

console.log(result);

/* Вывод:
[
  '23:59',
  '23',
  '59',
  index: 0,
  input: '23:59 25:99 1:2',
  groups: [Object: null prototype] { hours: '23', minutes: '59' }
]
*/

4. Атомы

4.1. Якоря

4.1.1. lineStart

  • Тип: Atom
  • Эквивалент: ^

lineStart — Якорь начала строки.

Принимает булево значение: true активирует якорь, false игнорирует атом.

{
  lineStart: true;
} // ^

4.1.2. lineEnd

  • Тип: Atom
  • Эквивалент: $

lineEnd — Якорь конца строки.

Принимает булево значение: true активирует якорь, false игнорирует атом.

{
  lineEnd: true;
} // $

4.2. Литералы и специальные символы

4.2.1. exactly

exactly — Сопоставляет точную последовательность символов (литерал).

Принимает строку, которая будет экранирована и использована как есть в регулярном выражении.

{
  exactly: 'foo';
} // foo
{
  exactly: '.';
} // \.
{
  exactly: '(';
} // \(

4.2.2. anyChar

  • Тип: Atom
  • Эквивалент: .

anyChar — Сопоставляет любой символ, кроме символов новой строки.

{
  anyChar: true;
} // .

4.2.3. tab

  • Тип: Atom
  • Эквивалент: \t

tab — Символ табуляции.

{
  tab: true;
} // \t

4.2.4. lineFeed

  • Тип: Atom
  • Эквивалент: \n

lineFeed — Символ перевода строки.

{
  lineFeed: true;
} // \n

4.2.5. carriageReturn

  • Тип: Atom
  • Эквивалент: \r

carriageReturn — Символ возврата каретки.

{
  carriageReturn: true;
} // \r

4.3. Символьные наборы

4.3.1. charIn

  • Тип: Atom
  • Эквивалент: [ ... ]

charIn — Символьный класс, сопоставляющий любой символ из указанного набора.

Принимает строку, описывающую набор символов в формате, аналогичном символьным классам регулярных выражений (диапазоны, экранированные символы и т.п.).

{
  charIn: 'a-z';
} // [a-z]
{
  charIn: 'a-zA-Z0-9';
} // [a-zA-Z0-9]
{
  charIn: 'abc';
} // [abc]

4.3.2. charNotIn

  • Тип: Atom
  • Эквивалент: [^ ...]

charNotIn — Отрицательный символьный класс, сопоставляющий любой символ, не входящий в указанный набор.

Принимает строку, описывающую набор символов в формате, аналогичном символьным классам регулярных выражений.

{
  charNotIn: 'a-z';
} // [^a-z]
{
  charNotIn: '0-9';
} // [^0-9]

4.4. Ссылки на группы

4.4.1. referenceTo

  • Тип: Atom
  • Эквивалент: \k<name>, \N

referenceTo — Ссылка на захваченную группу.

Принимает:

  • число — ссылка на группу по номеру (\N)
  • строку — ссылка на именованную группу (\k<name>)
{
  referenceTo: 1;
} // \1
{
  referenceTo: 'name';
} // \k<name>

4.5. Unicode свойства

4.5.1. unicodeProps

  • Тип: Atom
  • Эквивалент: \p{...}

unicodeProps — Сопоставляет символы на основе Unicode свойств.

Принимает строку, содержащую всё, что можно передать в \p{...} в обычном регулярном выражении (например, Letter, Number, Script=Latin и т.п.).

{
  unicodeProps: 'Letter';
} // \p{Letter}
{
  unicodeProps: 'Script=Latin';
} // \p{Script=Latin}

4.6. Символьные классы

Символьные классы — это атомы, которые принимают в качестве значения boolean. В отличие от якорей, где false игнорирует атом, для символьных классов значение false создаёт отрицательную версию класса (например, \D вместо \d, \W вместо \w).

4.6.1. digit

  • Тип: Atom
  • Эквивалент: \d, \D

digit — Символьный класс, сопоставляющий десятичные цифры.

Принимает булево значение: true сопоставляет любую десятичную цифру (0-9), false сопоставляет любой символ, не являющийся десятичной цифрой.

{
  digit: true;
} // \d
{
  digit: false;
} // \D

4.6.2. word

  • Тип: Atom
  • Эквивалент: \w, \W

word — Символьный класс, сопоставляющий символы слова.

Принимает булево значение: true сопоставляет латинские буквы (A-Z, a-z), десятичные цифры (0-9) и символ подчёркивания (_), false сопоставляет любой символ, не являющийся символом слова.

{
  word: true;
} // \w
{
  word: false;
} // \W

4.6.3. whitespace

  • Тип: Atom
  • Эквивалент: \s, \S

whitespace — Символьный класс, сопоставляющий пробельные символы.

Принимает булево значение: true сопоставляет пробельные символы, false сопоставляет любой символ, не являющийся пробельным.

{
  whitespace: true;
} // \s
{
  whitespace: false;
} // \S

4.6.4. boundary

  • Тип: Atom
  • Эквивалент: \b, \B

boundary — Якорь границы слова.

Принимает булево значение: true сопоставляет границу слова, false сопоставляет позицию, не являющуюся границей слова.

{
  boundary: true;
} // \b
{
  boundary: false;
} // \B