Assertion [U, N] ::
Утверждение 1 — ^
Утверждение 2 — $
Утверждение 3 — \b
Утверждение 4 — \B
Утверждение 5 — ( ? = Disjunction[?U, ?N] )
Утверждение 6 — ( ? ! Disjunction[?U, ?N] )
Утверждение 7 — ( ? <= Disjunction[?U, ?N] )
Утверждение 8 — ( ? <! Disjunction[?U, ?N] )
Регулярные выражения в JavaScript предлагают нам 8 вариантов оформления Утверждения (Assertion). Чтобы лучше понять как это работает нужно обратиться за помощью к примерам.
Утверждение № 1 — ^
Знак ^ определяет начало ввода или начало строки. То есть он указывает на начало.
Знаком ^ мы проверяем начало ввода или начало строки. Мы проверяем начинается ли строка с нужной последовательности символов или нет. Мы воспользуемся методом exec(), чтобы передавать в него строку и получать нужную нам информацию.
Давайте потестируем на такой строке:
var stroka = "aabbxxss"
// проверяем любое начало /^/.exec(stroka) ["", index: 0, input: "aabbxxss", groups: undefined] // проверяем один начальный символ строки, содержащий букву "a" /^a/.exec(stroka) ["a", index: 0, input: "aabbxxss", groups: undefined] // проверяем два начальных символа строки, содержащие буквы "aa" /^aa/.exec(stroka) ["aa", index: 0, input: "aabbxxss", groups: undefined] // проверяем три начальных символа строки, содержащие буквы "aaa" /^aaa/.exec(stroka) null //такое совпадение не найдено // проверяем два начальных символа строки, содержащие буквы "ab" /^ab/.exec(stroka) null //такое совпадение не найдено

Попытки отыскать другие символы из строки будут приводить к результату null
т. к. строка не начинается с этих символов
/^b/.exec(stroka) null /^bb/.exec(stroka) null /^x/.exec(stroka) null /^xx/.exec(stroka) null /^s/.exec(stroka) null /^ss/.exec(stroka) null
Логика работы Утверждения 1 — ^
Результат «Утверждение» (Assertion) :: ^ оценивается следующим образом:
1. Возвращает новый Matcher с параметрами (x, c), который ничего не захватывает и при вызове выполняет следующие шаги:
a. Утверждено: x является состоянием State.
b. Утверждено: c является продолжением Continuation.
c. Пусть e будет x-овым endIndex.
d. Если e = 0, или если Multiline является истиной true символ Input[e - 1] является одним из LineTerminator, тогда
i. Вернуть c(x).
e. Вернуть failure
.
Даже когда флаг y используется с шаблоном, знак ^ всегда соответствует только началу ввода Input или (если Multiline истинно true) началу строки.
Утверждение № 2 — $
Знак $ определяет конец ввода или конец строки. То есть он указывает на окончание.
Знаком $ мы проверяем конец ввода или конец строки. Мы проверяем заканчивается ли строка с нужной последовательности символов или нет. Мы воспользуемся методом exec(), чтобы передавать в него строку и получать нужную нам информацию.
Давайте потестируем на такой строке:
var stroka = "aabbxxss"
/$/.exec(stroka) ["", index: 8, input: "aabbxxss", groups: undefined] /s$/.exec(stroka) ["s", index: 7, input: "aabbxxss", groups: undefined] /ss$/.exec(stroka) ["ss", index: 6, input: "aabbxxss", groups: undefined] /sss$/.exec(stroka) null /xs$/.exec(stroka) null

Логика работы Утверждения 2 — $
Результат «Утверждение» (Assertion) :: $ оценивается следующим образом:
1. Возвращает новый Matcher с параметрами (x, c), который ничего не захватывает и при вызове выполняет следующие шаги:
a. Утверждено: x является состоянием State.
b. Утверждено: c является продолжением Continuation.
c. Пусть e будет x-овым endIndex.
d. Если e = InputLength, или если Multiline является истиной true и символ Input[e] является одним из LineTerminator, тогда
i. Вернуть c(x).
e. Вернуть failure
.
Утверждение № 3 — \b
Сочетание символов \b определяет границу буквы и символа. Например с позицией между буквой и пробелом внутри строки, а также началом и концом строки. То есть оно указывают на границу. Нужно чётко понимать какие символы JavaScript считает «буквами«, а какие «не буквами«.
Дополнительная информация
WordCharacters — это математический набор, который представляет собой объединение всех шестидесяти трех символов в «ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_» (буквы, числа и U+005F (LOW LINE — НИЖНЯЯ ЛИНИЯ) в блоке Unicode Basic Latin), и все символы c, для которых c отсутствует в этом наборе, но есть Canonicalize(c).
WordCharacters не может содержать более шестидесяти трех символов, если Unicode и IgnoreCase не имеют значения true.
Давайте протестируем на такой строке:
var stroka = "aa bb xx ss"
/\b/.exec(stroka) ["", index: 0, input: "aa bb xx ss", groups: undefined] /a\b/.exec(stroka) ["a", index: 1, input: "aa bb xx ss", groups: undefined] /\ba/.exec(stroka) ["a", index: 0, input: "aa bb xx ss", groups: undefined] /s\b/.exec(stroka) ["s", index: 10, input: "aa bb xx ss", groups: undefined] /\bs/.exec(stroka) ["s", index: 9, input: "aa bb xx ss", groups: undefined]

Другой пример. Другая строка:
var stroka = "aabbxx;ss;" /x\b/.exec(stroka) ["x", index: 5, input: "aabbxx;ss;", groups: undefined]

Теперь попробуем отыскать место строки, в котором символ буквы «x» находится справа от символа «небуквы».
/\bx/.exec(stroka) null
Такого результата не встретится, потому что обе буквы «x» слева от себя имеют по букве:
- первая буква «x» слева имеет букву «b«
- вторая буква «x» слева имеет первую букву «x«
ВАЖНО!
По умолчанию это утверждение работает только с буквами английского алфавита и цифрами. Не работает с русскими символами!
Читай публикацию JavaScript | Регулярные выражения | Обозначение (Notation), чтобы лучше разобраться в вопросе букв.

Логика работы Утверждения 3 — \b
Результат «Утверждение» (Assertion) :: \b оценивается следующим образом:
1. Возвращает новый Matcher с параметрами (x, c), который ничего не захватывает и при вызове выполняет следующие шаги:
a. Утверждено: x является состоянием State.
b. Утверждено: c является продолжением Continuation.
c. Пусть e будет x-овым endIndex.
d. Пусть a будет ! IsWordChar(e - 1).
e. Пусть b будет ! IsWordChar(e).
f. Если a является true и b является false, или если a является false и b является true, вернуть c(x).
g. Вернуть failure
.
Утверждение № 4 — \B
Сочетание символов \B определяет границу буквы и буквы. То есть оно указывают на границу. Нужно чётко понимать какие символы JavaScript считает «буквами«, а какие «не буквами«.
Пример:
var stroka = "a;b;xs" /\Ba/.exec(stroka) null /a\B/.exec(stroka) null
В этом случае получаем null
т. к. буква «a» не соседствует с другими буквами в этой строке.
/\Bx/.exec(stroka) null /x\B/.exec(stroka) ["x", index: 4, input: "a;b;xs", groups: undefined]
В этом случае получаем совпадение условия сопоставления. /\Bx/.exec(stroka)
возвращает null
т. к. буква «x» не соседствует слева с другими буквами в этой строке. /x\B/.exec(stroka)
возвращает объект (находит совпадение условия) т. к. буква «x» соседствует справа с другой буквой в этой строке.
Дополнительная информация
WordCharacters — это математический набор, который представляет собой объединение всех шестидесяти трех символов в «ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_» (буквы, числа и U+005F (LOW LINE — НИЖНЯЯ ЛИНИЯ) в блоке Unicode Basic Latin), и все символы c, для которых c отсутствует в этом наборе, но есть Canonicalize(c).
WordCharacters не может содержать более шестидесяти трех символов, если Unicode и IgnoreCase не имеют значения true.
Логика работы Утверждения 4 — \B
Результат «Утверждение» (Assertion) :: \B оценивается следующим образом:
1. Возвращает новый Matcher с параметрами (x, c), который ничего не захватывает и при вызове выполняет следующие шаги:
a. Утверждено: x является состоянием State.
b. Утверждено: c является продолжением Continuation.
c. Пусть e будет x-овым endIndex.
d. Пусть a будет ! IsWordChar(e - 1).
e. Пусть b будет ! IsWordChar(e).
f. Если a является true и b является true, или если a является false и b является false, вернуть c(x).
g. Вернуть failure
.
Утверждение № 5 — ( ? = Disjunction[?U, ?N] )
Указывает на границу двух последовательностей символов. Слева от конструкции мы пишем последовательность «оканчивающуюся», а внутри конструкции пишем последовательность «начинающуюся».
Мы как бы сопоставляем начало с концом. То есть мы ищем границы, в которых за «началом» следует «конец». Сопоставление ведётся по левой части от круглых скобок.
Если мы хотим найти в строке места где стыкуются «ав» и «не», то наше Утверждение будет иметь вид:
/ав(?=не)/
Пример работы утверждения:
var stroka = "aax;bbc;caabbx"
Мы хотим найти границы, где символ «а» слева, а символ «b» справа.
/a(?=b)/.exec(stroka) ["a", index: 10, input: "aax;bbc;caabbx", groups: undefined]

В ответ мы получаем объект, который указывает на 10 индекс в строке. То есть на границу 10 и 11 индексов. Значит такое совпадение было найдено.
Логика работы Утверждения 5 — ( ? = Disjunction[?U, ?N] )
1. Вычислите Disjunction с 1 в качестве аргумента направления direction, чтобы получить Matcher m. 2. Верните новый Matcher с параметрами (x, c), который захватывает m и при вызове выполняет следующие шаги: a. Утверждено: x является состоянием State. b. Утверждено: c является продолжением Continuation. c. Пусть d будет новым продолжением Continuation с параметрами (y), которое ничего не фиксирует и при вызове выполняет следующие шаги: i. Утверждено: y является состоянием State. ii. Вернуть y. d. Пусть r будет m(x, d). e. Если r является failure, вернуть failure. f. Пусть y будет r-ным состоянием State. g. Пусть cap будет y-ным captures Списка. h. Пусть xe будет x-ным endIndex. i. Пусть z будет состоянием State (xe, cap). j. Вернуть c(z).
Утверждение № 6 — ( ? ! Disjunction[?U, ?N] )
Указывает на границу двух последовательностей символов. Слева от конструкции мы пишем последовательность «оканчивающуюся», а внутри конструкции пишем последовательность «начинающуюся». Найдёт все сопоставления, которые не подпадают под это условие. Сопоставление ведётся по левой части.
Например, мы хотим получить все границы, где окончание — «ау«, а начало НЕ «ва«. То есть мы хотим найти те места в строке, где есть «ау«, но за ним НЕ следует «ва«.
Запись будет выглядеть так:
/ау(?!ва)/
Пример работы утверждения:
var stroka = "куауварыауси" /ау(?!ва)/.exec(stroka)

В ответ нам приходит объект, который начинается с индекса 8. Именно в этом месте найдено подходящее Утверждению соответствие. Сочетание «ауси» подходит, а сочетание символов «аува» исключается из отбора.
Логика работы Утверждения 6 — ( ? ! Disjunction[?U, ?N] )
1. Вычислите Disjunction с 1 в качестве аргумента направления direction, чтобы получить Matcher m. 2. Верните новый Matcher с параметрами (x, c), который захватывает m и при вызове выполняет следующие шаги: a. Утверждено: x является состоянием State. b. Утверждено: c является продолжением Continuation. c. Пусть d будет новым продолжением Continuation с параметрами (y), которое ничего не фиксирует и при вызове выполняет следующие шаги: i. Утверждено: y является состоянием State. ii. Вернуть y. d. Пусть r будет m(x, d). e. Если r не является failure, вернуть failure. f. Вернуть c(x).
Утверждение № 7 — ( ? <= Disjunction[?U, ?N] )
Утверждение 7 похоже на 5-ое. Только меняется направление сопоставления. Мы как бы сопоставляем конец с началом. То есть мы ищем границы, в которых «концу» предшествует искомое «начало». Сопоставление ведётся по правой части от круглых скобок.
Пример:
var stroka = "agcdefg"
Мы хотим найти то место, где перед буквой «g» есть буква «a»
/(?<=a)g/.exec(stroka) ["g", index: 1, input: "agcdefg", groups: undefined]

Логика работы Утверждения 7 — ( ? <= Disjunction[?U, ?N] )
1. Вычислите Disjunction с -1 в качестве аргумента направления direction, чтобы получить Matcher m. 2. Верните новый Matcher с параметрами (x, c), который захватывает m и при вызове выполняет следующие шаги: a. Утверждено: x является состоянием State. b. Утверждено: c является продолжением Continuation. c. Пусть d будет новым продолжением Continuation с параметрами (y), которое ничего не фиксирует и при вызове выполняет следующие шаги: i. Утверждено: y является состоянием State. ii. Вернуть y. d. Пусть r будет m(x, d). e. Если r является failure, вернуть failure. f. Пусть y будет r-ным состоянием State. g. Пусть cap будет y-ным captures Списка. h. Пусть xe будет x-ным endIndex. i. Пусть z будет состоянием State (xe, cap). j. Вернуть c(z).
Утверждение № 8 — ( ? <! Disjunction[?U, ?N] )
Утверждение 8 похоже на 6-ое. Только меняется направление сопоставления. Мы сопоставляем по условию в котором перед правой частью не стоит левая.
Пример:
var stroka = "agcdefg"
Мы хотим найти то место строки, где перед буквой «g» не стоит буква «a«. В нашем случае это последние два символа строки.
/(?<!a)g/.exec(stroka) ["g", index: 6, input: "agcdefg", groups: undefined]
В нашем случае нашлось сопоставление по условию. Нам вернулся объект с индексом 6. То есть такое соответствие нашлось между индексами 5 и 6. Мы как-бы сравнили справа налево.

Логика работы Утверждения 8 — ( ? <! Disjunction[?U, ?N] )
1. Вычислите Disjunction с -1 в качестве аргумента направления direction, чтобы получить Matcher m. 2. Верните новый Matcher с параметрами (x, c), который захватывает m и при вызове выполняет следующие шаги: a. Утверждено: x является состоянием State. b. Утверждено: c является продолжением Continuation. c. Пусть d будет новым продолжением Continuation с параметрами (y), которое ничего не фиксирует и при вызове выполняет следующие шаги: i. Утверждено: y является состоянием State. ii. Вернуть y. d. Пусть r будет m(x, d). e. Если r НЕ является failure, вернуть failure. f. Вернуть c(x).
IsWordChar ( e )
Абстрактная операция IsWordChar (Является ли символом слова) принимает аргумент e (целое число). При вызове он выполняет следующие шаги:
1. Если e = -1 или e является InputLength, вернуть false. 2. Пусть c будет символом Input[e]. 3. Если c находится в WordCharacters, вернуть true. 4. Вернуть false.
Информационные ссылки
Стандарт ECMAScript — Раздел «22.2.2.6 Assertion» — https://tc39.es/ecma262/#sec-assertion