Как найти конкретное слово в строке 1С, исключив похожие варианты с суффиксами?

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

Часто при разработке в 1С мы сталкиваемся с задачей поиска конкретного слова или артикула внутри длинного наименования. Проанализируем ситуацию: у нас есть массив строк, и нам нужно найти точное совпадение слова, например, hs28. При этом обычный поиск найдет нам и строку «нипель hs28», и строку «нипель hs28-01». Возникает вопрос: как организовать алгоритм так, чтобы находить только самостоятельное слово, отсекая варианты с суффиксами, прилипшими дефисами и цифрами?

Давайте разберем по шагам несколько подходов к решению этой задачи, от простейших манипуляций со строками до использования регулярных выражений и запросов базы данных.

Способ 1: Обертывание искомой строки пробелами

Первое, что приходит на ум — это искать строку вместе с пробелами. Если слово стоит отдельно, значит, слева и справа от него находятся пробелы. Посмотрим на пример кода, который попытались применить разработчики:


Если СтрНайти(Строка.Наименование, " " + ИскомаяСтрока + " ") > 0 Тогда
    // Слово найдено
КонецЕсли;

Однако этот подход не является универсальным. Что делать, если искомое слово находится в самом начале или в самом конце наименования? В таком случае пробела с одной из сторон не будет, и условие не сработает. Чтобы обойти эту проблему, можно добавить пробелы к самой исходной строке перед началом поиска. Рассмотрим подробнее этот трюк:


// Искусственно добавляем пробелы по краям исходной строки
СтрокаДляПоиска = " " + Строка.Наименование + " ";
СловоДляПоиска = " " + ИскомаяСтрока + " ";

Если СтрНайти(СтрокаДляПоиска, СловоДляПоиска) > 0 Тогда
    // Теперь мы найдем слово, даже если оно было в самом начале или конце
КонецЕсли;

Альтернативно, для проверки слов в конце строки можно использовать специализированную функцию 1С СтрЗаканчиваетсяНа(). Это решает часть проблемы, отсекая слова вроде «hs28-01».

Способ 2: Разделение строки на массив слов

Если в наименовании слова разделены строго пробелами, мы можем разбить всю строку на массив отдельных слов и затем искать в этом массиве точное совпадение. Выясним причину, почему это удобно: мы избавляемся от необходимости проверять левые и правые границы. Функция СтрРазделить() сделает эту работу за нас.


ВсеДопустимыеРазделители = " ";
НаборСлов = СтрРазделить(ВРег(Строка.Наименование), ВсеДопустимыеРазделители, Ложь);

// Ищем точное совпадение в массиве
Если НаборСлов.Найти(ВРег(ИскомаяСтрока)) <> Неопределено Тогда
    // Слово найдено как самостоятельная единица
КонецЕсли;

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

Способ 3: Нормализация строки (борьба со знаками препинания)

У предыдущих двух подходов (с пробелами и разделением) есть одна серьезная уязвимость — знаки препинания. Что, если строка записана как «нипель hs28, черный» или «нипель hs28.»? Алгоритмы с пробелами не найдут слово, так как к нему «прилипла» запятая или точка.

Чтобы избежать ложных пропусков, перед выполнением поиска строку необходимо «нормализовать». Разберем, как это сделать. Мы должны заменить все возможные знаки препинания (запятые, точки, дефисы, слеши, скобки) на обычные пробелы. После этого строка «нипель hs28-01, красный» превратится в «нипель hs28 01 красный». И уже после этого можно смело применять добавление пробелов по краям:


// Очищаем строку от лишних символов
ТекстОчищенный = СтрЗаменить(Строка.Наименование, ",", " ");
ТекстОчищенный = СтрЗаменить(ТекстОчищенный, ".", " ");
ТекстОчищенный = СтрЗаменить(ТекстОчищенный, "-", " ");

// Теперь безопасно ищем
Если СтрНайти(" " + ТекстОчищенный + " ", " " + ИскомаяСтрока + " ") > 0 Тогда
    // Точное попадание
КонецЕсли;

Способ 4: Поиск в запросе 1С (Оператор ПОДОБНО)

Если мы ищем строку не в оперативной памяти (в массиве), а непосредственно в базе данных (например, в справочнике «Номенклатура»), использование циклов будет крайне неэффективным. Свой поиск лучше организовать через запрос.

В языке запросов 1С для поиска точного слова, обрамленного пробелами или находящегося на краях строки, используется комбинация из четырех условий оператора ПОДОБНО. Проанализируем этот классический паттерн:


ВЫБРАТЬ
    Номенклатура.Ссылка,
    Номенклатура.Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    (Номенклатура.Наименование = &ИскомаяСтрока
    ИЛИ Номенклатура.Наименование ПОДОБНО &ИскомаяСтрока + " %"
    ИЛИ Номенклатура.Наименование ПОДОБНО "% " + &ИскомаяСтрока
    ИЛИ Номенклатура.Наименование ПОДОБНО "% " + &ИскомаяСтрока + " %")

Эти четыре условия покрывают все возможные ситуации:

  1. Строка состоит только из этого слова.
  2. Слово находится в самом начале (после него пробел).
  3. Слово находится в самом конце (перед ним пробел).
  4. Слово находится в середине (пробелы с обеих сторон).

Способ 5: Регулярные выражения (Самый надежный метод)

Для сложного текстового поиска лучшим инструментом исторически являются регулярные выражения. Долгое время в 1С приходилось использовать COM-объекты для этих целей, но начиная с версии платформы 8.3.23, регулярные выражения поддерживаются «из коробки».

Для платформы 1С версии 8.3.23 и выше:
Мы можем использовать новую функцию СтрНайтиПоРегулярномуВыражению(). Шаблон поиска будет выглядеть так: (^|\s)hs28(\s|$). Он означает, что искомая строка должна либо начинаться с начала текста (или пробела), и заканчиваться пробелом (или концом текста). Это решает задачу в одну элегантную строчку кода:


Паттерн = "(^|\s)" + ИскомаяСтрока + "(\s|$)";
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(Строка.Наименование, Паттерн);

Если РезультатПоиска.Количество() > 0 Тогда
    // Нашли точное совпадение слова
КонецЕсли;

Для старых версий платформы:
Если ваша платформа ниже 8.3.23, и код выполняется на сервере под управлением ОС Windows, вы можете использовать COM-объект VBScript.RegExp. Разберем пример создания и настройки такого объекта:


RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина; // Игнорируем регистр
RegExp.Global = Истина;     // Ищем все вхождения
// Границы слова с учетом пробелов или начала/конца строки
RegExp.Pattern = "(^|\s)" + ИскомаяСтрока + "(\s|$)"; 

Если RegExp.Test(Строка.Наименование) Тогда
    // Слово найдено
КонецЕсли;

Способ 6: Полнотекстовый поиск данных (ППД)

Если основная задача — это сопоставление номенклатуры при загрузке данных извне (например, из Excel или XML), и поиск идет по всей базе, настоятельно рекомендуется использовать механизм Полнотекстового поиска (ППД).

ППД изначально спроектирован так, чтобы разбивать весь текст в базе на отдельные слова (индексы). Если вы передадите в полнотекстовый поиск строку hs28, он самостоятельно найдет все записи, где это слово присутствует как самостоятельная единица, и гарантированно проигнорирует слова, написанные слитно с дефисами или другими символами (вроде «hs28-01»). Это самый быстрый и архитектурно правильный способ поиска по справочникам в 1С.

← На главную