Почему не ищется номенклатура по наименованию и как это исправить в 1С

Программист 1С v8.3 (Обычные формы)
← На главную

Часто программисты 1С сталкиваются с ситуацией, когда при программном поиске номенклатуры метод возвращает пустую ссылку, хотя визуально данные в справочнике присутствуют. Эта проблема может парализовать работу механизмов загрузки данных из внешних источников или обработки документов. В рамках данной статьи мы подробно разберем причины возникновения такой ошибки, проанализируем типичные промахи в коде и рассмотрим эффективные способы поиска данных.

Разбор основной проблемы: нюансы метода НайтиПоНаименованию

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

НайтиПоНаименованию(Наименование, ТочноеСоответствие, Родитель, Владелец)

По умолчанию параметр ТочноеСоответствие имеет значение Истина. Это означает, что если в вашей строке поиска написано "Масло доз", а в справочнике элемент называется "Масло доз." (с точкой в конце), 1С не найдет этот объект. Разберем основные причины неудачного поиска:

  1. Различие в символах: Наличие лишних точек, запятых, скобок или кавычек.
  2. Невидимые символы: При копировании данных из Excel часто попадаются "неразрывные пробелы" (символ с кодом 160). Обычная функция СокрЛП их не удаляет, и для системы строки "Товар" и "Товар " становятся абсолютно разными.
  3. Регистр и лидирующие пробелы: Хотя поиск в 1С обычно нечувствителен к регистру, наличие пробела в самом начале наименования в справочнике может привести к отрицательному результату.

Рассмотрим пример кода, который часто приводит к ошибкам, и то, как его можно подкорректировать:


// Неточный поиск может помочь, если наименование начинается одинаково
СсылкаНаНоменклатуру = Справочники.Номенклатура.НайтиПоНаименованию(Стр.Наименование, Ложь);
Если СсылкаНаНоменклатуру.Пустая() Тогда
    Сообщить("Товар не найден: " + Стр.Наименование);
КонецЕсли;

Однако помните: если вы укажете Ложь (неточное соответствие), 1С будет искать вхождение строки только с начала. Если вы ищете "Сливочное", а в базе оно "Масло сливочное", метод все равно вернет пустую ссылку.

Оптимизация производительности: критическая ошибка работы в цикле

Проанализируем исходный код из сообщения автора. Огромной ошибкой является создание объектов ТаблицаЗначений, ОписаниеТипов и ПостроительЗапроса внутри цикла Для Каждого. Это приводит к колоссальным затратам оперативной памяти и процессорного времени.

Выясним причину: при каждой итерации цикла система заново выделяет память под структуру таблицы и инициализирует сложный объект построителя. Если в вашей таблице 1000 строк, система сделает это 1000 раз!

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


// Правильно: выносим инициализацию за пределы цикла
ТаблицаДляПостроителя = Новый ТаблицаЗначений;
ОписаниеСправочника = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
ТаблицаДляПостроителя.Колонки.Добавить("НоменклатураТП", ОписаниеСправочника);

Построитель = Новый ПостроительЗапроса;
// Дальнейшая настройка построителя...

Для Каждого Стр Из тзРезультат Цикл
    // Внутри цикла только работа с данными
    НайденнаяСсылка = Справочники.Номенклатура.НайтиПоНаименованию(Стр.Наименование);
    
    Если Не НайденнаяСсылка.Пустая() Тогда
        ТабСтр = ТаблицаДляПостроителя.Добавить();
        ТабСтр.НоменклатураТП = НайденнаяСсылка;
        // Работа с отборами
    КонецЕсли;
КонецЦикла;

Использование запросов и оператора ПОДОБНО

Если стандартный метод поиска не справляется, наиболее гибким инструментом становится запрос. Рассмотрим ситуацию, когда нам нужно найти номенклатуру, в названии которой содержится определенное слово или часть фразы. Для этого используется оператор ПОДОБНО.

Разберем пример запроса для поиска с использованием спецсимвола % (любое количество произвольных символов):


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Наименование ПОДОБНО &НаименованиеПоиска";

// Ищем вхождение в любом месте строки
Запрос.УстановитьПараметр("НаименованиеПоиска", "%" + Стр.Наименование + "%");
РезультатЗапроса = Запрос.Выполнить();

Этот метод гораздо надежнее, так как позволяет игнорировать точки в конце или дополнительные слова в начале названия. Однако будьте осторожны: если запрос найдет несколько подходящих элементов, вам придется программно решить, какой из них выбрать (например, первый из выборки или тот, что не помечен на удаление).

Продвинутые методы: Полнотекстовый поиск и нормализация строк

Для сложных случаев, когда названия могут содержать переставленные слова или опечатки, рекомендуется использовать механизм Полнотекстового поиска (ПП), встроенный в платформу 1С. В отличие от обычного сравнения строк, ПП учитывает морфологию языка.

Также полезно перед поиском проводить нормализацию строк. Давайте проанализируем, как можно "очистить" строку поиска от лишнего мусора:

  1. Используйте функцию СтрЗаменить для удаления точек, запятых и спецсимволов.
  2. Заменяйте неразрывные пробелы Символы.НПП на обычные пробелы.
  3. Применяйте СокрЛП для удаления пробелов по краям.

Пример функции очистки строки:


Функция ОчиститьСтрокуДляПоиска(Знач ВхСтрока)
    Результат = СокрЛП(ВхСтрока);
    Результат = СтрЗаменить(Результат, Символы.НПП, ""); // Удаляем неразрывные пробелы
    Результат = СтрЗаменить(Результат, ".", "");       // Удаляем точки
    Результат = СтрЗаменить(Результат, ",", "");       // Удаляем запятые
    Возврат Результат;
КонецФункции

Резюме

Подведем итоги нашего исследования. Если вы столкнулись с тем, что НайтиПоНаименованию возвращает пустую ссылку:

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

← На главную