Механизмы lookahead и lookbehind пришли из
регулярных выражений и используются для проверки контекста символов без
включения этого контекста в итоговое совпадение. В библиотеке Inputmask
эти конструкции особенно полезны при создании сложных динамических
масок, где поведение ввода зависит от соседних символов, положения
курсора или уже введённых данных.
Inputmask поддерживает регулярные выражения внутри масок через режим
regex, а также использует внутреннюю логику проверки
шаблонов, где lookahead/lookbehind позволяют строить интеллектуальные
ограничения.
Позитивный lookahead проверяет, что после текущей позиции присутствует определённая последовательность.
Синтаксис:
(?=pattern)
Конструкция означает:
«совпадение допустимо только если дальше идёт pattern»
При этом сам pattern не включается в результат.
Inputmask({
regex: "\\d(?=\\d{3})"
}).mask("#test");
Разбор:
| Конструкция | Значение |
|---|---|
\d |
цифра |
(?=\d{3}) |
после неё должны идти ещё три цифры |
Подойдут:
1234
5678
Не подойдут:
12
123
Lookahead часто используется для проверки конца ввода.
Пример:
Inputmask({
regex: "\\d+(?= USD)"
}).mask("#currency");
Подходит:
100 USD
250 USD
Не подходит:
100 EUR
100US D
Здесь:
(?= USD)
требует наличие строки " USD" после числа.
Inputmask({
regex: "\\+7(?=\\s\\(\\d{3}\\))"
}).mask("#phone");
Проверяется:
наличие +7
далее обязательно:
Подходящий ввод:
+7 (777)
Неподходящий:
+7123
+7-777
Inputmask({
regex: "[A-Z]{2}(?=\\d{4})\\d{4}"
}).mask("#code");
Структура:
| Фрагмент | Значение |
|---|---|
[A-Z]{2} |
две буквы |
(?=\d{4}) |
дальше должны идти четыре цифры |
\d{4} |
сами цифры |
Подходящие значения:
AB1234
ZX9999
Негативный lookahead проверяет отсутствие шаблона после текущей позиции.
Синтаксис:
(?!pattern)
Означает:
«дальше НЕ должно быть pattern»
Inputmask({
regex: "^(?!000)\\d{3}$"
}).mask("#code");
Разбор:
| Конструкция | Значение |
|---|---|
^ |
начало строки |
(?!000) |
строка не должна начинаться с 000 |
\d{3} |
три цифры |
Допустимо:
123
555
901
Недопустимо:
000
Inputmask({
regex: "^(?!admin).*"
}).mask("#login");
Запрещён ввод:
admin
administrator
admin123
Разрешён:
user
manager
root
Inputmask({
regex: "^(?!.*\\.exe$).+"
}).mask("#filename");
Здесь:
(?!.*\.exe$)
означает:
строка не должна заканчиваться на
.exe
Подходит:
photo.png
archive.zip
notes.txt
Не подходит:
virus.exe
setup.exe
Lookbehind проверяет наличие шаблона перед текущей позицией.
Синтаксис:
(?<=pattern)
Означает:
«перед текущей позицией должен быть pattern»
Inputmask({
regex: "(?<=USD)\\d+"
}).mask("#money");
Подходит:
USD100
USD250
Не подходит:
EUR100
RUB500
Здесь число допустимо только если перед ним находится
"USD".
Inputmask({
regex: "(?<=ID-)\\d{5}"
}).mask("#id");
Разрешено:
ID-12345
ID-99999
Запрещено:
12345
CODE-12345
Inputmask({
regex: "(?<=:)\\d{2}"
}).mask("#time");
Допускается:
12:30
08:45
После двоеточия обязательно две цифры.
Негативный lookbehind проверяет отсутствие шаблона перед текущей позицией.
Синтаксис:
(?<!pattern)
Означает:
«перед текущей позицией НЕ должен находиться pattern»
Inputmask({
regex: "(?<!-)\\d+"
}).mask("#number");
Не допускается число после минуса.
Подходит:
123
555
Не подходит:
-123
Inputmask({
regex: "(?<!__)\\w+"
}).mask("#username");
Исключаются последовательности с двойным подчёркиванием перед словом.
Lookahead и lookbehind вместе называют lookaround-конструкциями.
Пример:
Inputmask({
regex: "^(?!.*\\.\\.)[A-Za-z0-9._%+-]+(?<!\\.)@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
}).mask("#email");
Разбор:
| Конструкция | Назначение |
|---|---|
(?!.*\.\.) |
запрет двойных точек |
(?<!\.) |
запрет точки перед @ |
@[A-Za-z0-9.-]+ |
доменная часть |
\.[A-Za-z]{2,} |
доменная зона |
Допустимо:
user@mail.com
test.user@gmail.com
Недопустимо:
user..name@mail.com
user.@mail.com
Inputmask({
regex: "(?<=\\[)\\d+(?=\\])"
}).mask("#array");
Проверяется число внутри квадратных скобок.
Подходит:
[123]
[999]
Не подходит:
123
(123)
Inputmask({
regex: "^(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,}$"
}).mask("#password");
Используются несколько lookahead одновременно.
Условия:
| Проверка | Конструкция |
|---|---|
| хотя бы одна заглавная буква | (?=.*[A-Z]) |
| хотя бы одна цифра | (?=.*\d) |
| хотя бы один спецсимвол | (?=.*[!@#$%^&*]) |
| минимум 8 символов | .{8,} |
Подходящие варианты:
Test123!
Qwerty9@
Inputmask({
regex: "^(?=.{10}$)(?=.*\\d)(?=.*[A-Z])[A-Z0-9]+$"
}).mask("#doc");
Условия:
Lookahead и lookbehind увеличивают сложность регулярного выражения. Особенно это заметно в Inputmask при:
Проблемные конструкции:
(?=.*a)(?=.*b)(?=.*c)(?=.*d)
или:
(?!.*forbidden)
на очень длинных строках.
Не все JavaScript-движки одинаково поддерживают lookbehind.
Поддержка появилась относительно поздно:
| Среда | Поддержка |
|---|---|
| Современный Chrome | есть |
| Firefox | есть |
| Safari старых версий | проблемы |
| Internet Explorer | отсутствует |
Из-за этого некоторые Inputmask-конфигурации с
(?<=...) и (?<!...) могут работать
нестабильно в старых браузерах.
Вместо:
(?<=USD)\d+
часто используют:
USD(\d+)
С последующим извлечением группы.
Такой подход:
Lookaround чаще всего применяется именно в режиме
regex.
Пример подключения:
Inputmask({
regex: "^(?=.*[A-Z])(?=.*\\d).+$"
}).mask("#field");
Inputmask начинает интерпретировать всю маску как полноценное регулярное выражение.
Lookaround:
Группа захвата:
(...)
сохраняет найденный фрагмент.
Пример:
USD(\d+)
Здесь:
(\d+)
будет доступно как группа.
В lookahead:
(?=\d+)
данные не сохраняются.
Inputmask({
regex: "^(?=.*[A-Z])(?=.*\\d)(?!.*\\s)(?=.*[_-]).{6,20}$"
}).mask("#login");
Требования:
| Проверка | Значение |
|---|---|
(?=.*[A-Z]) |
минимум одна заглавная |
(?=.*\d) |
минимум одна цифра |
(?!.*\s) |
запрет пробелов |
(?=.*[_-]) |
наличие _ или - |
.{6,20} |
длина от 6 до 20 |
Подходит:
Admin_1
User-99
Не подходит:
admin
test test
USERONLY
Inputmask позволяет комбинировать регулярные выражения с динамическими правилами:
Inputmask({
regex: "^(?:(?=\\d{10}$)\\d+|(?=\\d{12}$)\\d+)$"
}).mask("#number");
Разрешаются:
Другие длины запрещены.
Ошибка:
regex: "\d+(?=\w)"
Правильно:
regex: "\\d+(?=\\w)"
В строках JavaScript обратный слэш нужно экранировать.
(?<=USD)\d+
может не работать в Internet Explorer.
Конструкция:
^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@#$%^&+=]).{8,}$
при непрерывном вводе может вызывать заметные задержки.
Плохо:
(?=(?!(?=.*abc)).*)
Лучше:
(?!.*abc)
Вместо гигантского regex:
Inputmask({
regex: "..."
})
часть проверок лучше переносить:
onBeforePastevalidatorЭто повышает: