При обработке номенклатурных позиций, загрузке прайс-листов или сопоставлении каталогов часто возникает задача: проверить, содержит ли наименование товара хотя бы одну подстроку из заданного перечня значений. Разберем основные способы решения этой задачи на платформе 1С:Предприятие, их достоинства, недостатки и нюансы производительности.
Если строка наименования уже получена в оперативную память (например, при обходе выборки или в объекте), наиболее простым, надежным и производительным вариантом является последовательный перебор элементов массива с вызовом встроенной функции СтрНайти.
Разберем реализацию этого алгоритма по шагам:
СтрРазделить (доступна начиная с платформы 8.3.6).СтрНайти.Прервать, чтобы не выполнять лишних итераций.Посмотрим на пример программного кода:
СтрокаШаблонов = "145 R12c,155 R12c,5.00 R12c,155 R13c,145 R13c,155 R13c";
МассивПодстрок = СтрРазделить(СтрокаШаблонов, ",", Ложь);
НаименованиеТовара = Номенклатура.Наименование;
СовпадениеНайдено = Ложь;
Для Каждого Подстрока Из МассивПодстрок Цикл
ОчищеннаяПодстрока = СокрЛП(Подстрока);
Если ПустаяСтрока(ОчищеннаяПодстрока) Тогда
Продолжить;
КонецЕсли;
Если СтрНайти(НаименованиеТовара, ОчищеннаяПодстрока) > 0 Тогда
СовпадениеНайдено = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если СовпадениеНайдено Тогда
// Выполняем требуемые действия
КонецЕсли;
Важная деталь: функция СтрНайти в платформе 1С выполняет поиск без учета регистра символов. Если требуется обеспечить строгое совпадение с нестандартными кодировками или гарантировать единый формат, можно предварительно привести строки к нижнему регистру с помощью функции НРег.
Проанализируем ситуацию, когда необходимо проверить совпадение строкового шаблона без предварительного разложения строки на массив. В среде Windows для этого можно использовать объект COMОбъект("VBScript.RegExp"), объединив все искомые подстроки через логический оператор «или» (символ |).
Рассмотрим пример кода:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина; // Игнорировать регистр
RegExp.Global = Ложь;
// Формируем паттерн вида: (145 R12c|155 R12c|5\.00 R12c)
// Обратите внимание: спецсимволы регулярных выражений (например, точку) необходимо экранировать
RegExp.Pattern = "(145 R12c|155 R12c|5\.00 R12c|155 R13c|145 R13c)";
Если RegExp.Test(Номенклатура.Наименование) Тогда
// Подстрока найдена
КонецЕсли;
Ограничения метода:
COMОбъект работает исключительно в операционных системах Windows. Если сервер 1С работает под управлением Linux, данный код вызовет исключение.., +, *, (, ), [, ] в регулярных выражениях имеют специальное назначение. Если в подстроках встречаются размеры шин вроде 5.00, точку нужно экранировать обратным слэшем \, иначе она будет означать «любой символ».Если задача заключается в том, чтобы сразу отобрать из базы данных все элементы справочника Номенклатура, удовлетворяющие условиям, можно динамически сформировать текст запроса с условиями ПОДОБНО, объединенными через ИЛИ.
Разберем пример динамического формирования текста запроса:
СтрокаШаблонов = "145 R12c,155 R12c,5.00 R12c,155 R13c,145 R13c";
МассивПодстрок = СтрРазделить(СтрокаШаблонов, ",", Ложь);
Запрос = Новый Запрос;
ТекстУсловий = "";
НомерПараметра = 0;
Для Каждого Подстрока Из МассивПодстрок Цикл
ОчищеннаяПодстрока = СокрЛП(Подстрока);
Если ПустаяСтрока(ОчищеннаяПодстрока) Тогда
Продолжить;
КонецЕсли;
НомерПараметра = НомерПараметра + 1;
ИмяПараметра = "Шаблон" + НомерПараметра;
Если ТекстУсловий <> "" Тогда
ТекстУсловий = ТекстУсловий + " ИЛИ ";
КонецЕсли;
ТекстУсловий = ТекстУсловий + "Номенклатура.Наименование ПОДОБНО &" + ИмяПараметра;
Запрос.УстановитьПараметр(ИмяПараметра, "%" + ОчищеннаяПодстрока + "%");
КонецЦикла;
Если НомерПараметра > 0 Тогда
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| " + ТекстУсловий;
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка найденных элементов
КонецЦикла;
КонецЕсли;
При использовании запросов с условием ПОДОБНО "%...%" следует учитывать технические особенности работы СУБД:
% в начале шаблона делает невозможным использование индексов по полю Наименование. СУБД будет выполнять полное сканирование таблицы, что при больших справочниках (от десятков тысяч записей) приведет к существенному падению производительности и блокировкам.ПОДОБНО определяется настройками сортировки (Collation) базы данных. На Microsoft SQL Server поиск, как правило, нечувствителен к регистру, однако на некоторых конфигурациях PostgreSQL сравнение может выполняться с учетом регистра.%, _ или квадратные скобки, их необходимо экранировать с помощью конструкции СПЕЦСИМВОЛ.Резюме: для проверки одной конкретной строки в памяти оптимально использовать связку СтрРазделить + СтрНайти с досрочным выходом из цикла через Прервать. Если же требуется масштабная выборка из базы, для ускорения работы рекомендуется использовать механизм полнотекстового поиска (ПолнотекстовыйПоиск.СоздатьСписок), который использует специальные индексы и работает значительно быстрее неиндексированных условий ПОДОБНО.