Как проверить строку на соответствие маске без использования запроса в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

Разберем довольно распространенную задачу, с которой сталкиваются разработчики в 1С: как проверить строковое значение (например, номер телефона, ИНН или артикул) на строгое соответствие определенному формату или маске. Очень часто при отсутствии очевидных встроенных функций разработчики прибегают к нестандартным обходным путям. Посмотрим на пример, который стал отправной точкой нашего обсуждения.

Для проверки телефонного номера разработчик использовал язык запросов и оператор ПОДОБНО:


&НаСервере
Функция ПроверитьНаМаску(С, Маска)
    З = Новый Запрос(
    "ВЫБРАТЬ 1 ГДЕ
    |    ВЫБОР
    |        КОГДА &С ПОДОБНО &Маска
    |            ТОГДА ИСТИНА
    |        ИНАЧЕ ЛОЖЬ
    |    КОНЕЦ ");
    З.УстановитьПараметр("С", С);
    З.УстановитьПараметр("Маска", Маска);
    Выборка = З.Выполнить().Выбрать();
    Возврат Выборка.Следующий();
КонецФункции

&НаСервере
Процедура ПриЗаписиНаСервереПеред(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    Для Каждого Строка ИЗ ТекущийОбъект.КонтактнаяИнформация Цикл
        Если Строка.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Телефон") Тогда
            Если Не ПроверитьНаМаску(Строка.Представление, "+7([0-9][0-9][0-9])[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]") Тогда
                Сообщить("Телефон: " + Строка.Представление + " не соответствует формату, исправьте перед записью !");
                Отказ = истина;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Проанализируем эту ситуацию. Использование объекта Запрос в цикле при обходе табличной части контактной информации — это серьезный удар по производительности. На каждую строку контактной информации инициализируется менеджер запросов, компилируется текст, выполняется запрос к СУБД (пусть и без обращения к реальным таблицам) и обрабатывается результат. Очевидно, что для простой строковой валидации этот метод избыточен. Давайте рассмотрим более правильные и легковесные решения этой задачи.

Решение 1: Использование встроенных регулярных выражений (платформа 1С 8.3.23 и выше)

Разберем самый современный и эффективный способ. Долгое время разработчики ждали нативную поддержку регулярных выражений, и, начиная с платформы 1С:Предприятие версии 8.3.23, эта функциональность была добавлена. Встроенный язык теперь имеет полноценную поддержку регулярных выражений на базе диалекта ICU (International Components for Unicode).

Теперь мы можем решить задачу изящно с помощью функции СтрПодобнаПоРегулярномуВыражению. Посмотрим на пример кода, который полностью заменит функцию с запросом:


&НаСервере
Функция ПроверитьНомерТелефона(СтрокаТелефона)
    // Шаблон для телефона: +7(999)999-99-99
    МаскаRegExp = "^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$";
    Возврат СтрПодобнаПоРегулярномуВыражению(СтрокаТелефона, МаскаRegExp);
КонецФункции

В этом примере регулярное выражение ^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$ строго описывает структуру номера. Рассмотрим подробнее, что умеет новая платформа помимо этого:

  1. СтрНайтиПоРегулярномуВыражению — позволяет найти первое совпадение подстроки по заданному шаблону.
  2. СтрНайтиВсеПоРегулярномуВыражению — возвращает массив всех совпадений в исходной строке.
  3. СтрЗаменитьПоРегулярномуВыражению — мощный инструмент для очистки строк (например, если нам нужно оставить в номере телефона только цифры).

Если ваша база работает на платформе 8.3.23 или новее, смело используйте этот подход. Он работает быстро, не требует внешних компонент и является стандартом разработки.

Решение 2: Использование COM-объекта VBScript.RegExp (для платформ ниже 8.3.23)

Если обновление платформы пока невозможно, проанализируем альтернативный вариант. Мы можем использовать встроенные возможности операционной системы Windows посредством инициализации COM-объекта. Объект VBScript.RegExp позволяет работать с регулярными выражениями без установки дополнительных библиотек или DLL.

Перепишем нашу функцию проверки на использование COM-объекта:


&НаСервере
Функция ПроверитьНаМаскуЧерезCOM(СтрокаДляПроверки)
    RegExp = Новый COMОбъект("VBScript.RegExp");
    
    // Устанавливаем маску регулярного выражения
    RegExp.Pattern = "^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$";
    
    // Настройки объекта: 
    // IgnoreCase - игнорировать регистр
    // Global - искать все вхождения
    RegExp.IgnoreCase = Истина;
    RegExp.Global = Ложь;
    
    // Метод Test возвращает Истина, если строка соответствует маске
    Возврат RegExp.Test(СтрокаДляПроверки);
КонецФункции

Этот метод работает в сотни раз быстрее, чем инициализация запроса в цикле. Важно отметить: этот подход будет работать только на серверах под управлением ОС Windows. Если ваш сервер 1С развернут на Linux, создать данный COM-объект не удастся.

Решение 3: Валидация через XML-схемы (XDTO)

Рассмотрим кроссплатформенный подход без использования запросов и новых функций платформы, который подойдет для старых версий 1С (в том числе на серверах Linux). Мы можем использовать возможности валидации типов XDTO.

Платформа позволяет проверять данные на соответствие фасету типа, описанному в XML-схеме (включая маску pattern). Это более громоздкий способ, но он работает исключительно встроенными средствами:


&НаСервере
Функция ПроверитьСтрокуПоСхемеXML(СтрокаПроверки, Маска)
    // Формируем текст простой XML-схемы с регулярным выражением
    ТекстСхемы = "
    |
    |  
    |    
    |      
    |    
    |  
    |";
    
    // Читаем схему
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(ТекстСхемы);
    ПостроительDOM = Новый ПостроительDOM;
    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    // Создаем фабрику XDTO по нашей схеме
    ПостроительСхем = Новый ПостроительСхемXML;
    СхемаXML = ПостроительСхем.СоздатьСхемуXML(ДокументDOM);
    НаборСхем = Новый НаборСхемXML;
    НаборСхем.Добавить(СхемаXML);
    Фабрика = Новый ФабрикаXDTO(НаборСхем);
    
    // Пытаемся проверить значение
    ТипЗначения = Фабрика.Тип("", "MaskedString");
    Попытка
        ПроверенноеЗначение = Фабрика.Создать(ТипЗначения, СтрокаПроверки);
        Возврат Истина;
    Исключение
        Возврат Ложь;
    КонецПопытки;
КонецФункции

Здесь мы динамически генерируем XML-схему, в которой создаем свой собственный строковый тип с ограничением по паттерну. При попытке создать значение этого типа через объект ФабрикаXDTO, платформа проверяет его по маске схемы. Если возникает исключение — строка маске не соответствует. Этот метод хоть и выглядит сложно, но отрабатывает быстрее базы данных и не имеет зависимостей от ОС.

Решение 4: Использование свойства "Маска" для элементов формы

Не забудем про встроенные средства пользовательского интерфейса. Если нам не требуется жесткая серверная проверка, мы можем предотвратить некорректный ввод непосредственно в интерфейсе пользователя. Для полей ввода (расширение поля формы для текстового документа) существует свойство Маска.

Выделив нужное поле на форме, в палитре свойств можно задать маску, например: +7(999)999-99-99. В таком случае платформа автоматически подставит статические символы +7( ) - - и не позволит пользователю ввести буквы вместо цифр.

Однако этот способ имеет существенные ограничения:

  1. Маска интерфейса не защищает данные, если запись происходит программно (например, при загрузке из других систем или обмене).
  2. В некоторых типовых конфигурациях (например, 1С:Управление торговлей) контактная информация вводится через сложные формы-помощники или динамические поля, где статические маски формы не всегда применимы.
  3. Пользователь не сможет ввести "добавочный" номер или иностранный номер в другом формате, если поле ввода жестко ограничено. В современных реалиях часто требуется валидировать данные гибко, а не блокировать ввод на уровне клавиш.

Подводим итоги

Мы детально разобрали, как избавиться от конструкции ПОДОБНО в запросе при решении задач форматирования. Используйте свойство Маска на управляемых формах для удобства пользователей. Для надежной валидации данных перед записью используйте нативную функцию платформы СтрПодобнаПоРегулярномуВыражению. Если версия платформы не позволяет, применяйте объект VBScript.RegExp на Windows-серверах или схему XDTO как универсальный и независимый инструмент проверки.

← На главную