При работе с текстовыми полями (например, с реквизитом Комментарий в документах или справочниках) часто возникает необходимость найти записи по ключевым словам или фразам. Однако пользователи могут вводить текст с произвольным количеством пробелов, переносов строк и специальных символов. В обычной разработке на встроенном языке 1С для решения таких задач используется функция СтрЗаменить(), но в языке запросов выбор инструмента зависит от используемой версии платформы и архитектурных требований. Рассмотрим подробнее, как решить эту задачу различными способами.
Если требуется найти документ по нескольким ключевым словам или фрагментам текста, не обращая внимания на количество пробелов и спецсимволов между ними, наилучшим решением в самом запросе является оператор ПОДОБНО с шаблоном поиска.
Вместо точного равенства строке формируется маска с символом процента (%), который обозначает любую последовательность произвольных символов (включая пробелы, табуляции и переносы строк).
Разберем по шагам пример формирования запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажа.Ссылка КАК Ссылка,
| Продажа.Комментарий КАК Комментарий
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Продажа
|ГДЕ
| Продажа.Комментарий ПОДОБНО &ШаблонПоиска";
Запрос.УстановитьПараметр("ШаблонПоиска", "%слово1%слово2%слово3%");
РезультатЗапроса = Запрос.Выполнить();
При таком подходе СУБД успешно найдет все документы, в комментарии которых последовательно встречаются указанные ключевые слова, независимо от наличия между ними лишних пробелов или символов перевода строки.
Проанализируем современные возможности платформы. Начиная с версии 8.3.20, в язык запросов 1С была официально добавлена встроенная функция СтрЗаменить(), а также функции СокрЛ(), СокрП(), СокрЛП(), СтрНайти(), ВРег(), НРег() и ДлинаСтроки().
Поиск подстроки внутри СтрЗаменить() в языке запросов выполняется без учета регистра. Если требуется удалить символы перевода строки или пробелы непосредственно в тексте запроса, их можно передать через параметры запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ
| СтрЗаменить(СтрЗаменить(Док.Комментарий, &Пробел, """"), &СимволПС, """") ПОДОБНО &ИскомыйТекст";
Запрос.УстановитьПараметр("Пробел", " ");
Запрос.УстановитьПараметр("СимволПС", Символы.ПС);
Запрос.УстановитьПараметр("ИскомыйТекст", "%искомоезначение%");
Важно: Использование функций обработки строк к полям таблиц базы данных в секции ГДЕ может предотвращать использование индексов СУБД, что снижает скорость выполнения запроса на больших объемах данных.
Выясним, как поступить, если выборку необходимо выполнять на старых версиях платформы без снижения производительности СУБД. В этом случае мы можем сначала выгрузить первичные результаты запроса во временную таблицу или объект ТаблицаЗначений, после чего обработать текстовые поля стандартными средствами встроенного языка.
Разберем данный подход на примере:
Выгрузить().Комментарий с использованием функции СтрЗаменить().
ТЗРезультат = Запрос.Выполнить().Выгрузить();
ТЗРезультат.Колонки.Добавить("ОчищенныйКомментарий", Новый ОписаниеТипов("Строка"));
Для Каждого Стр Из ТЗРезультат Цикл
Текст = Стр.Комментарий;
Текст = СтрЗаменить(Текст, " ", "");
Текст = СтрЗаменить(Текст, Символы.ПС, "");
Текст = СтрЗаменить(Текст, Символы.ВК, "");
Стр.ОчищенныйКомментарий = Текст;
КонецЦикла;
ПараметрыОтбора = Новый Структура("ОчищенныйКомментарий", "ИскомыйТекстБезПробелов");
НайденныеСтроки = ТЗРезультат.НайтиСтроки(ПараметрыОтбора);
Посмотрим на ситуацию со стороны архитектуры системы. Текстовый комментарий предназначен в первую очередь для пользователя, а не для системного поиска. Попытка строить бизнес-логику и отборы на анализе неструктурированного текста часто приводит к замедлению работы системы.
Если типовую конфигурацию нельзя снимать с поддержки, рассмотрим альтернативные варианты оптимизации:
ПередЗаписью для нужного документа. При сохранении документа программа автоматически очистит комментарий от лишних символов и запишет его в отдельное поле или в независимый регистр сведений. В дальнейшем запросы будут выполнять отбор по подготовленному индексированному полю мгновенно.