Regex-маски в библиотеке Inputmask
позволяют описывать сложные правила ввода через регулярные выражения,
однако механизм их работы существенно отличается от полноценной
обработки regex в JavaScript. Внутренний движок Inputmask анализирует
ввод посимвольно, формируя допустимое состояние маски на каждом этапе
ввода. Из-за этого возникают ограничения, которые отсутствуют при
обычной проверке строки через RegExp.
Важно понимать ключевой принцип:
/^\d{4}$/
В обычном JavaScript это выражение проверяет уже готовую строку.
В Inputmask:
Inputmask({
regex: "\\d{4}"
}).mask("#code");
маска должна уметь работать во время ввода каждого символа.
Это фундаментально меняет поведение regex.
Inputmask не получает готовое значение целиком. Пользователь вводит символы постепенно:
1
12
123
1234
На каждом шаге движок обязан определить:
Из-за этого некоторые конструкции регулярных выражений становятся несовместимыми с механизмом маскирования.
Положительный просмотр вперёд:
(?=...)
поддерживается только в простых сценариях.
Пример:
Inputmask({
regex: "(?=.*[A-Z]).*"
}).mask("#field");
Теоретически выражение требует наличие хотя бы одной заглавной буквы.
Однако при вводе:
a
ab
abc
Inputmask не может окончательно определить, появится ли заглавная буква позже.
Результат зависит от:
На практике сложные lookahead-конструкции работают нестабильно.
Lookbehind:
(?<=...)
(?<!...)
поддерживается значительно хуже.
Причина связана с тем, что Inputmask движется слева направо и ориентирован на потоковый ввод.
Пример:
Inputmask({
regex: "(?<=USD)\\d+"
});
Для корректной проверки движку необходимо анализировать предыдущий контекст, что плохо сочетается с динамическим построением маски.
Во многих случаях lookbehind:
Якоря:
^
$
в обычном regex обозначают начало и конец строки.
В Inputmask строка постоянно находится в промежуточном состоянии.
Пример:
Inputmask({
regex: "^\\d{5}$"
});
Во время ввода:
1
12
123
значение ещё не завершено.
Из-за этого Inputmask вынужден ослаблять строгую проверку.
Поведение может отличаться:
jitMasking;clearIncomplete.Regex-движки JavaScript используют сложный механизм возвратов (backtracking).
Пример:
(a|ab)c
Обычный regex способен:
a;ab.Inputmask работает иначе.
Он старается минимизировать количество возвратов, поскольку маска должна реагировать мгновенно при вводе каждого символа.
Поэтому сложные альтернативы:
(a|ab|abc|abcd)
могут приводить к:
Сложные конструкции:
((ab(cd|ef))+|(xy(z|w))+)
резко увеличивают сложность обработки.
Inputmask строит внутреннее дерево состояний маски. Глубокая вложенность приводит к экспоненциальному росту вариантов.
Симптомы:
Особенно критично это становится при:
Конструкции:
.*
.+
[a-z]+
опасны для Inputmask.
Причина заключается в неопределённой длине.
Пример:
Inputmask({
regex: ".*@.*"
});
Такой шаблон теоретически допускает бесконечное количество состояний.
Inputmask вынужден постоянно пересчитывать:
Это вызывает нестабильность.
Гораздо безопаснее:
Inputmask({
regex: "[^@]{1,50}@[a-z]{2,20}\\.[a-z]{2,10}"
});
Некоторые regex-конструкции способны вызывать катастрофическое количество проверок.
Классический пример:
(a+)+
или:
([a-z]+)*
В обычном JavaScript это уже потенциальная проблема.
В Inputmask ситуация усугубляется тем, что проверка происходит после каждого символа.
Даже строка длиной 20–30 символов может вызывать:
Настоящая рекурсия regex:
(?R)
или аналогичные PCRE-конструкции не поддерживаются вообще.
Inputmask использует JavaScript RegExp, а JavaScript не поддерживает рекурсивные regex.
Поэтому невозможно корректно описать:
JavaScript поддерживает Unicode-флаги:
/u
Однако Inputmask не всегда корректно взаимодействует с Unicode-классами.
Проблемный пример:
\p{L}
или:
\p{Script=Cyrillic}
Причины:
Некоторые Unicode-конструкции:
Paste-события значительно сложнее обычного ввода.
При вставке строки:
+7 (777) 123-45-67
Inputmask вынужден:
Сложные regex ухудшают paste-производительность многократно.
Особенно опасны:
(.+)*
(.*)+
(\w+)+
Флаги Jav * aScript:
g
m
s
y
u
не используются в Inputmask напрямую.
Regex передаётся как строка:
regex: "\\d+"
а не как объект RegExp.
Поэтому многие привычные возможности недоступны.
Например:
/\d+/g
не имеет смысла внутри Inputmask.
Inputmask ориентирован на однострочный ввод.
Конструкции:
^
$
в multiline-сценариях ведут себя непредсказуемо.
Переносы строк:
\n
обычно несовместимы с классическими input-полями.
Regex для textarea работают ограниченно и требуют отдельного тестирования.
Слишком большое количество optional-блоков:
(a)?(b)?(c)?(d)?(e)?
создаёт огромное количество возможных состояний.
Inputmask вынужден хранить и проверять варианты:
a
ab
abc
abd
acd
...
Количество комбинаций растёт экспоненциально.
Последствия:
Regex вроде:
\d+
не имеют верхней границы.
Для Inputmask это плохо.
Движок не знает:
Рекомендуется всегда задавать диапазон:
\d{1,10}
Regex-маски плохо подходят для сценариев, где значение зависит от сложного контекста.
Например:
февраль → максимум 28 дней
апрель → максимум 30 дней
Теоретически regex можно сделать крайне сложным:
(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])
Но полноценная календарная логика быстро становится неподдерживаемой.
Для таких случаев лучше использовать:
postValidation;onBeforePaste;Сложность regex напрямую влияет на отзывчивость интерфейса.
Inputmask выполняет:
после каждого действия пользователя.
Даже относительно небольшой regex может стать проблемой:
([a-zA-Z0-9._%+-]+)+@([a-z0-9.-]+)+\.[a-z]{2,}
Особенно на:
Главная ошибка при работе с regex-масками — попытка использовать Inputmask как полноценный валидатор.
Маскирование и финальная валидация — разные задачи.
Inputmask хорошо подходит для:
Но сложную бизнес-валидацию лучше выполнять отдельно:
const isValid = complexRegex.test(value);
после завершения ввода.
Плохо:
.*
Хорошо:
.{1,50}
Плохо:
(a|ab|abc|abcd|abcde)
Хорошо:
ab(c(de)?)?
Плохо:
(a)?(b)?(c)?(d)?
Хорошо:
(a(b(c(d)?)?)?)?
Плохо:
regex: "сверхсложное_правило_на_300_символов"
Хорошо:
Inputmask({
regex: "\\d{2}\\.\\d{2}\\.\\d{4}",
postValidation(buffer) {
return validateDate(buffer.join(""));
}
});
Опасно:
(.+)*
Безопаснее:
.{0,100}
Inputmask не должен становиться единственным уровнем проверки.
Regex для:
часто несовместимы с Inputmask.
Regex может быть валиден только в финальном виде, но Inputmask обязан поддерживать все этапы ввода.
Чем сложнее regex, тем хуже:
Regex-маски особенно полезны для:
Примеры удачных шаблонов:
\\d{4}
[A-Z]{2}\\d{6}
[0-9]{5}
[a-z0-9._%+-]{1,30}@[a-z0-9.-]{1,30}\\.[a-z]{2,6}
В этих случаях Inputmask работает стабильно, быстро и предсказуемо.