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