При разработке и доработке конфигураций 1С разработчики нередко сталкиваются с задачей валидации и фильтрации строковых данных непосредственно на уровне языка запросов. Типичный сценарий — проверка соответствия строки определенному формату, например, когда строка должна представлять собой конструкцию вида NNN/NNN/, где N — это цифра, а количество цифр в каждом блоке может варьироваться от 1 до 3 (например, 1/1/, 22/150/, 999/5/).
Разберем детально, какие возможности предоставляет язык запросов платформы 1С:Предприятие, почему стандартный оператор ПОДОБНО имеет ограничения, и какие есть эффективные способы решения этой задачи как на уровне запроса, так и на уровне архитектуры прикладного решения.
Проанализируем работу строкового оператора ПОДОБНО. В языке запросов 1С этот оператор транслируется в конструкцию LIKE соответствующей СУБД (Microsoft SQL Server, PostgreSQL, Oracle и др.). Набор специальных символов для сопоставления шаблонов в 1С строго ограничен:
% — любая последовательность произвольных символов произвольной длины (включая нулевую длину)._ — ровно один произвольный символ.[...] — ровно один одиночный символ из указанного диапазона или перечисления (например, [0-9]).[^...] — ровно один одиночный символ, кроме входящих в указанный диапазон или перечисление.СПЕЦСИМВОЛ — символ экранирования управляющих знаков.В отличие от механизмов регулярных выражений (RegEx), в языке запросов 1С отсутствуют квантификаторы повторений (такие как +, * или диапазон {1,3}). По этой причине задать конструкцию «от одной до трех цифр» одним простым символом в шаблоне невозможно.
Рассмотрим прямолинейное решение, к которому чаще всего прибегают разработчики. Если длина числового блока строго ограничена от 1 до 3 символов, то каждый блок может состоять из одной, двух или трех цифр. Это дает 3 варианта для первого блока и 3 варианта для второго, то есть суммарно 9 возможных комбинаций.
Посмотрим на пример формирования условия в секции ГДЕ:
ВЫБРАТЬ
Таблица.Ссылка КАК Ссылка,
Таблица.СтроковоеПоле КАК СтроковоеПоле
ИЗ
Справочник.Номенклатура КАК Таблица
ГДЕ
Таблица.СтроковоеПоле ПОДОБНО "[0-9]/[0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9]/[0-9][0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9]/[0-9][0-9][0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9]/[0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9]/[0-9][0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9]/[0-9][0-9][0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9][0-9]/[0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9][0-9]/[0-9][0-9]/"
ИЛИ Таблица.СтроковоеПоле ПОДОБНО "[0-9][0-9][0-9]/[0-9][0-9][0-9]/"
Особенности способа:
ИЛИ выросло бы до 100).Разберем более изящный алгоритмический прием, который позволяет описать шаблон любой длины через фиксацию структуры и наложение запретов. Вместо перечисления всех разрешенных комбинаций мы формулируем правила, которым обязана соответствовать строка, соединенные оператором И.
Сформулируем правила валидности строки:
ПОДОБНО "%/%/".НЕ ПОДОБНО "/%".НЕ ПОДОБНО "%/%/%/".НЕ ПОДОБНО "%//%".НЕ ПОДОБНО "%[^0-9/]%".НЕ ПОДОБНО "%[0-9][0-9][0-9][0-9]%".Посмотрим на пример реализации в запросе:
ВЫБРАТЬ
Таблица.Ссылка КАК Ссылка,
Таблица.СтроковоеПоле КАК СтроковоеПоле
ИЗ
Справочник.Номенклатура КАК Таблица
ГДЕ
Таблица.СтроковоеПоле ПОДОБНО "%/%/"
И НЕ Таблица.СтроковоеПоле ПОДОБНО "/%"
И НЕ Таблица.СтроковоеПоле ПОДОБНО "%/%/%/"
И НЕ Таблица.СтроковоеПоле ПОДОБНО "%//%"
И НЕ Таблица.СтроковоеПоле ПОДОБНО "%[^0-9/]%"
И НЕ Таблица.СтроковоеПоле ПОДОБНО "%[0-9][0-9][0-9][0-9]%"
Такой подход читается компактнее и легко модифицируется: если максимальное количество цифр увеличится до 5, достаточно изменить лишь последнее отрицание на проверку 6 цифр подряд.
Проанализируем ситуацию, когда проверку можно перенести на уровень встроенного языка — например, при постобработке выборки запроса или перед записью объекта. Начиная с версии платформы 8.3.23, в 1С появились встроенные нативные методы для работы с регулярными выражениями.
Рассмотрим функцию СтрСоответствуетПоРегулярномуВыражению(). Она позволяет проверить строку по регулярному выражению ^\d{1,3}/\d{1,3}/$ буквально в одну строку кода.
// Пример проверки строки на соответствие шаблону
ШаблонРегЭксп = "^\d{1,3}/\d{1,3}/$";
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если СтрСоответствуетПоРегулярномуВыражению(Выборка.СтроковоеПоле, ШаблонРегЭксп) Тогда
// Строка полностью соответствует формату [1-3 цифры]/[1-3 цифры]/
ОбработатьКорректнуюСтроку(Выборка.Ссылка);
КонецЕсли;
КонецЦикла;
Преимущества использования нативных регулярных выражений:
Выясним причину замечаний о падении производительности при использовании сложных условий ПОДОБНО в запросах. Когда запрос содержит условия вида ПОДОБНО "%..." (с маской в начале) или отрицания НЕ ПОДОБНО, оптимизатор СУБД не может применить индексный поиск (Index Seek) по строковому полю. Это приводит к полному сканированию таблицы или индекса (Table Scan / Index Scan).
Если таблица содержит сотни тысяч или миллионы записей, постоянное выполнение таких запросов вызывает сильную нагрузку на процессор и дисковую подсистему сервера СУБД.
Рассмотрим правильные архитектурные альтернативы:
ЧисловаяЧасть1 и ЧисловаяЧасть2. В этом случае проверка в запросе сводится к быстрому индексному условию:
ГДЕ
Таблица.ЧисловаяЧасть1 МЕЖДУ 0 И 999
И Таблица.ЧисловаяЧасть2 МЕЖДУ 0 И 999
СоответствуетШаблону с типом Булево и включенным индексированием. В модуле объекта в процедуре ПередЗаписью вычисляем значение этого флага с помощью регулярного выражения. Тогда запрос будет максимально быстрым:
ГДЕ
Таблица.СоответствуетШаблону = ИСТИНА
Выбор конкретного решения зависит от контекста задачи: для разовых сервисных обработок и отчетов подойдет метод исключений или перебор условий, а для высоконагруженных рабочих механизмов наилучшим решением будет предварительный расчет флага при записи или нормализация реквизитов.