При работе с текстовыми данными в 1С программисты часто сталкиваются с задачей поиска конкретного слова (лексемы) в строке. Стандартный подход с использованием оператора ПОДОБНО и маски %Текст% не всегда эффективен, так как он находит вхождения части слова в более длинные конструкции. Например, при поиске аббревиатуры "АБС" система выдаст и "Датчик АБС" (что правильно), и "Топливный абсорбер" (что является ложным срабатыванием). Рассмотрим детально, как решить эту задачу различными методами, начиная от классических запросов и заканчивая современными возможностями платформы.
Разберем классический подход. Проблема оператора ПОДОБНО в том, что он не понимает границ слова. Чтобы выделить именно слово "АБС", нам нужно убедиться, что оно окружено либо пробелами, либо знаками препинания, либо находится в самом начале или конце строки. Проанализируем ситуацию и составим комбинированное условие.
Для корректного поиска слова "АБС" в тексте нам придется описать все возможные позиции этого слова. Рассмотрим пример кода запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
(Номенклатура.Наименование ПОДОБНО "АБС %"
ИЛИ Номенклатура.Наименование ПОДОБНО "% АБС %"
ИЛИ Номенклатура.Наименование ПОДОБНО "% АБС"
ИЛИ Номенклатура.Наименование = "АБС")
Важный нюанс: Этот метод не учитывает знаки препинания, такие как скобки или тире. Если в базе есть позиция "Тормозные (АБС) колодки", вышеуказанный запрос ее не найдет. Чтобы расширить поиск, нам пришлось бы добавлять условия для каждого спецсимвола, что крайне неэффективно и тяжело читаемо.
Выясним причину, по которой предыдущий метод кажется громоздким. Нам приходится отдельно обрабатывать начало и конец строки. Существует изящный "хак", позволяющий упростить условие. Мы можем программно добавить пробелы к проверяемому полю прямо в тексте запроса. Проанализируем этот подход:
ВЫБРАТЬ
Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
" " + Номенклатура.Наименование + " " ПОДОБНО "% АБС %"
Добавляя пробел в начало и в конец наименования, мы гарантируем, что искомое слово "АБС" всегда будет окружено пробелами, даже если оно стояло в самом начале или в самом конце оригинальной строки. Однако помните, что такая конструкция полностью отключает использование индексов СУБД, так как мы применяем функцию к индексируемому полю. На больших таблицах это приведет к значительному замедлению работы.
Если в вашей конфигурации включен полнотекстовый поиск, это самый правильный и быстрый способ поиска целых слов. Полнотекстовый индекс специально оптимизирован для морфологического анализа и поиска лексем. Посмотрим на пример программного кода для получения списка подходящих ссылок:
СписокСсылок = Новый Массив;
СтрокаПоиска = """АБС"""; // Используем кавычки для поиска точного слова
РезультатПоиска = ПолнотекстовыйПоиск.СоздатьСписок(СтрокаПоиска, 100);
РезультатПоиска.ПерваяЧасть();
Для Каждого СтрокаРезультата Из РезультатПоиска Цикл
Если ТипЗнч(СтрокаРезультата.Значение) = Тип("СправочникСсылка.Номенклатура") Тогда
СписокСсылок.Добавить(СтрокаРезультата.Значение);
КонецЕсли;
КонецЦикла;
Преимущества метода:
Недостатки: поиск зависит от актуальности индекса. Если товар был создан секунду назад, он не попадет в результат, пока не отработает регламентное задание по обновлению индекса ППД.
Рассмотрим долгожданное обновление платформы. Начиная с версии 8.3.24, в языке запросов появился оператор СООТВЕТСТВУЕТ (в англоязычном варианте MATCHES). Это позволяет использовать всю мощь регулярных выражений (RegExp) непосредственно на уровне СУБД.
Для поиска слова "АБС" как отдельной единицы в регулярных выражениях используется метасимвол границы слова \b. Разберем, как это выглядит в коде:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование СООТВЕТСТВУЕТ &ШаблонПоиска";
Запрос.УстановитьПараметр("ШаблонПоиска", ".*\bАБС\b.*");
Этот метод является наиболее современным и надежным. Он автоматически учитывает любые символы, не являющиеся буквами или цифрами, как границы слова.
Если ваша платформа ниже версии 8.3.24, а использовать ППД невозможно, рекомендуется применить двухэтапную фильтрацию. На первом этапе мы выбираем данные "широким" запросом, а на втором — уточняем результат с помощью объекта VBScript.RegExp.
Проанализируем алгоритм:
ПОДОБНО "%АБС%". Это быстро отсечет 99% ненужных данных.
РегВыражение = Новый COMОбъект("VBScript.RegExp");
РегВыражение.IgnoreCase = Истина;
РегВыражение.Global = Ложь;
РегВыражение.Pattern = "\bАБС\b";
ТаблицаРезультатов = Запрос.Выполнить().Выгрузить();
ИндексСтроки = 0;
Пока ИндексСтроки < ТаблицаРезультатов.Количество() Цикл
Строка = ТаблицаРезультатов[ИндексСтроки];
Если НЕ РегВыражение.Test(Строка.Наименование) Тогда
ТаблицаРезультатов.Удалить(Строка);
Иначе
ИндексСтроки = ИндексСтроки + 1;
КонецЕсли;
КонецЦикла;
Такой комбинированный подход позволяет сохранить производительность системы и добиться идеальной точности поиска.
Выясним, какой метод лучше в конкретной ситуации. Если вы работаете на современной платформе 8.3.24+, всегда используйте СООТВЕТСТВУЕТ. Это стандарт индустрии. Если база большая (сотни тысяч позиций номенклатуры) и поиск выполняется часто, настройте Полнотекстовый поиск. Для разовых задач в небольших базах вполне подойдет метод с добавлением пробелов в условии ПОДОБНО, несмотря на его неоптимальность.
Помните, что создание поискового индекса в виде отдельного регистра сведений (где наименование разбито на отдельные слова) — это также отличная практика для высоконагруженных систем. В этом случае поиск будет сводиться к простому равенству, что является самой быстрой операцией для любой СУБД.