Продвинутые регулярные выражения

Библиотека Inputmask поддерживает не только базовые шаблоны вида 9, a, *, но и полноценные регулярные выражения, позволяющие строить сложные динамические маски с условной логикой, проверками диапазонов и контекстной валидацией ввода.

Продвинутые регулярные выражения используются в следующих сценариях:

  • валидация нестандартных форматов;
  • поддержка нескольких вариантов ввода;
  • проверка диапазонов чисел;
  • условные группы;
  • динамические маски;
  • сложные идентификаторы;
  • почтовые индексы;
  • серийные номера;
  • технические форматы;
  • кастомные токены.

Режим regex

Самый прямой способ использования регулярных выражений — параметр regex.

Inputmask({
    regex: "[A-Z]{3}-\\d{4}"
}).mask("#code");

Разрешённый ввод:

ABC-1234
XYZ-0001

Недопустимые значения:

ab-1234
ABCD-123

Здесь:

Конструкция Назначение
[A-Z] заглавная буква
{3} ровно три символа
\\d цифра
{4} четыре цифры

Экранирование символов

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

Неверно:

regex: "\d{4}"

Верно:

regex: "\\d{4}"

Либо через литерал RegExp:

regex: /\d{4}/

Использование диапазонов

Диапазоны чисел

Inputmask({
    regex: "([1-9]|[1-9][0-9]|100)"
}).mask("#percent");

Разрешаются числа:

1–100

Разбор выражения:

Часть Значение
[1-9] 1–9
[1-9][0-9] 10–99
100 отдельное значение

Проверка IP-адреса

Inputmask({
    regex:
        "((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){3}" +
        "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])"
}).mask("#ip");

Поддерживаются адреса:

192.168.0.1
255.255.255.255
10.0.0.5

Запрещаются:

999.999.999.999
300.1.1.1

Альтернативы через |

Оператор | позволяет создавать множественные сценарии ввода.

Inputmask({
    regex: "(YES|NO)"
}).mask("#answer");

Допустимые значения:

YES
NO

Несколько телефонных форматов

Inputmask({
    regex:
        "(\\+7\\s\\(\\d{3}\\)\\s\\d{3}-\\d{2}-\\d{2})|" +
        "(8\\s\\d{3}\\s\\d{3}-\\d{2}-\\d{2})"
}).mask("#phone");

Поддержка:

+7 (777) 123-45-67
8 777 123-45-67

Группы захвата

Регулярные выражения поддерживают группировку через круглые скобки.

(AB|CD)-\d{2}

Подходит:

AB-12
CD-99

Не подходит:

EF-12

Необязательные группы

Символ ? делает группу необязательной.

Inputmask({
    regex: "\\+7\\s?\\d{10}"
}).mask("#phone");

Поддерживаются оба варианта:

+77771234567
+7 7771234567

Повторения

Точное количество

regex: "[A-Z]{5}"

Ровно 5 букв.


Диапазон повторений

regex: "\\d{2,5}"

От 2 до 5 цифр.


Неограниченное количество

regex: "[a-z]+"

Одна или более строчных букв.


Якоря начала и конца строки

Начало строки

regex: "^\\d+"

Строка должна начинаться с цифр.


Конец строки

regex: "\\.com$"

Строка должна оканчиваться на .com.


Полное совпадение

regex: "^\\d{4}$"

Только четыре цифры без дополнительных символов.


Проверка email

Inputmask({
    regex:
        "[a-zA-Z0-9._%+-]+@" +
        "[a-zA-Z0-9.-]+\\." +
        "[a-zA-Z]{2,}"
}).mask("#email");

Разрешаются:

user@test.com
admin123@mail.ru

Сложная проверка пароля

Inputmask({
    regex:
        "(?=.*[a-z])" +
        "(?=.*[A-Z])" +
        "(?=.*\\d)" +
        ".{8,}"
}).mask("#password");

Требования:

  • минимум 8 символов;
  • хотя бы одна заглавная буква;
  • хотя бы одна строчная буква;
  • хотя бы одна цифра.

Позитивный просмотр вперёд — (?=...)

Lookahead позволяет проверять условие без включения его в итоговое совпадение.

(?=.*\d)

Означает:

где-то далее должна присутствовать цифра.

Пример:

Inputmask({
    regex: "(?=.*\\d)(?=.*[A-Z]).{6,}"
}).mask("#secure");

Негативный просмотр вперёд — (?!...)

Запрещает определённые последовательности.

Inputmask({
    regex: "^(?!admin).*"
}).mask("#login");

Недопустимо:

admin
administrator

Проверка HEX-цветов

Inputmask({
    regex: "#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"
}).mask("#color");

Поддержка:

#FFF
#00FFAA

UUID и GUID

Inputmask({
    regex:
        "[0-9a-fA-F]{8}-" +
        "[0-9a-fA-F]{4}-" +
        "[0-9a-fA-F]{4}-" +
        "[0-9a-fA-F]{4}-" +
        "[0-9a-fA-F]{12}"
}).mask("#uuid");

Пример:

550e8400-e29b-41d4-a716-446655440000

Проверка MAC-адреса

Inputmask({
    regex:
        "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}"
}).mask("#mac");

Поддерживается:

AA:BB:CC:DD:EE:FF

Комбинирование с обычными масками

Регулярные выражения могут использоваться внутри definitions.

Inputmask({
    mask: "HH:MM",
    definitions: {
        "H": {
            validator: "[0-2]"
        },
        "M": {
            validator: "[0-5]"
        }
    }
}).mask("#time");

Контекстная валидация

Более сложные проверки реализуются функцией validator.

Inputmask({
    mask: "99-99",
    definitions: {
        "9": {
            validator: function(chrs, maskset, pos) {
                return /[0-9]/.test(chrs);
            }
        }
    }
}).mask("#custom");

Проверка диапазона времени

Inputmask({
    regex: "([01][0-9]|2[0-3]):[0-5][0-9]"
}).mask("#time");

Допустимо:

23:59
00:00
14:30

Недопустимо:

29:99
24:61

Проверка даты

Inputmask({
    regex:
        "(0[1-9]|[12][0-9]|3[01])\\/" +
        "(0[1-9]|1[0-2])\\/" +
        "\\d{4}"
}).mask("#date");

Нестрогие и строгие шаблоны

Нестрогий режим

regex: "\\d+"

Подходит любая длина числа.


Строгий режим

regex: "^\\d{10}$"

Только 10 цифр.


Производительность сложных регулярных выражений

Слишком сложные шаблоны могут вызывать:

  • задержки ввода;
  • подвисания интерфейса;
  • повышенную нагрузку на CPU;
  • медленную обработку мобильных устройств.

Особенно опасны:

(.+)+

или

(.*a){10}

Подобные конструкции способны вызывать catastrophic backtracking.


Оптимизация выражений

Плохо

(a|aa|aaa)+

Лучше

a+

Плохо

(.*)(\d)

Лучше

.*\d

Использование greedy

Inputmask({
    regex: "\\d+",
    greedy: false
}).mask("#number");

greedy: false уменьшает агрессивное заполнение шаблона.


Unicode и национальные символы

Поддержка кириллицы:

Inputmask({
    regex: "[А-Яа-яЁё\\s]+"
}).mask("#russian");

Латиница и кириллица одновременно

Inputmask({
    regex: "[A-Za-zА-Яа-яЁё]+"
}).mask("#mixed");

Проверка URL

Inputmask({
    regex:
        "(https?:\\/\\/)?" +
        "([\\w-]+\\.)+[\\w-]+" +
        "(\\/[\\w- ./?%&=]*)?"
}).mask("#url");

Использование postValidation

Для сложной логики после проверки регулярного выражения.

Inputmask({
    regex: "\\d+",
    postValidation: function(buffer) {
        const value = buffer.join("");

        return Number(value) <= 1000;
    }
}).mask("#range");

Кастомные определения с regex

Inputmask.extendDefinitions({
    "X": {
        validator: "[A-F0-9]",
        casing: "upper"
    }
});

Использование:

Inputmask("XXXX-XXXX").mask("#hex");

Проверка VIN-номеров

Inputmask({
    regex: "[A-HJ-NPR-Z0-9]{17}"
}).mask("#vin");

VIN исключает символы:

I
O
Q

Серийные номера

Inputmask({
    regex: "[A-Z]{2}-\\d{6}-[A-Z]"
}).mask("#serial");

Пример:

AB-123456-Z

Регулярные выражения и динамическая маска

Inputmask({
    mask: [
        "999-999",
        "AA-9999"
    ],
    keepStatic: false
}).mask("#dynamic");

Inputmask автоматически выбирает подходящий сценарий ввода.


Проверка банковского счёта

Inputmask({
    regex: "\\d{20}"
}).mask("#bank");

Проверка IBAN

Inputmask({
    regex:
        "[A-Z]{2}\\d{2}[A-Z0-9]{1,30}"
}).mask("#iban");

Проверка JSON-подобных структур

Для сложных структур регулярные выражения становятся трудно поддерживаемыми.

Плохая практика:

regex: "\\{.*\\}"

Лучше:

  • использовать парсер JSON;
  • выполнять серверную проверку;
  • комбинировать Inputmask с отдельной логикой валидации.

Ограничения regex в Inputmask

Регулярные выражения не подходят для:

  • сложного синтаксического анализа;
  • вложенных структур;
  • HTML;
  • XML;
  • полноценных JSON-документов;
  • математических выражений;
  • контекстно-зависимых языков.

В подобных случаях применяются:

  • парсеры;
  • AST;
  • серверная валидация;
  • специализированные библиотеки.