repattern Спецификация 1.0.0-beta.0
Спецификация встраиваемого DSL для создания регулярных выражений в JavaScript на основе декларативных схем.
Языки: Английский
Участие: GitHub teplostanski/repattern-spec (создать issue, открытые issues)
Аннотация
Спецификация repattern — встраиваемого DSL для создания регулярных выражений в JavaScript на основе декларативных схем типа Scheme, которые преобразуются в объекты RegExp.
Схемы представляют собой человекочитаемый формат описания шаблонов, альтернативный написанию регулярных выражений вручную.
Note
Для эффективного использования данной спецификации рекомендуется понимать термины и принципы работы регулярных выражений, так как схемы описывают те же концепции в декларативном формате.
Содержание
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).
- lineStart
- lineEnd
- exactly
- anyChar
- tab
- lineFeed
- carriageReturn
- referenceTo
- charIn
- charNotIn
- unicodeProps
- digit
- word
- whitespace
- boundary
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 может находиться только внутри атомов‑секвенсоров.
Таблица соотношений параметров и атомов-секвенсоров:
| Параметр | Атом-секвенсор |
|---|---|
times | repeat |
lazy | repeat, zeroOrMore, maybe |
group | repeat, zeroOrMore, maybe, grouped, anyOf |
optionally | anyOf |
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
- Тип: AtomSequencer
- Эквивалент:
*
zeroOrMore — Создаёт группу с квантификатором *.
Повторяет подшаблон ноль или более раз.
Поддерживаемые параметры
Объект params может содержать (см. Объект параметров params):
Примеры
const scheme = [{ zeroOrMore: [{ exactly: 'foo' }] }];
// Результат: /(?:foo)*/
const scheme = [
{
zeroOrMore: [
{ charIn: 'a-z' },
{ params: { group: 'letters', lazy: true } },
],
},
];
// Результат: /(?<letters>[a-z]*?)/
3.1.3. maybe
- Тип: AtomSequencer
- Эквивалент:
?
maybe — Создаёт группу с квантификатором ? (повторить подшаблон ноль или один раз).
Делает подшаблон необязательным.
Поддерживаемые параметры
Объект params может содержать (см. Объект параметров params):
Примеры
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
- Тип: AtomSequencer
- Эквивалент:
|
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
- Тип: Atom
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