В процессе разработки на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с ситуацией, когда данные из внешних систем приходят в виде «полного наименования» (пути через разделитель, например: "Группа/Подгруппа/Элемент"). Если в справочнике используется глубокая иерархия (в нашем случае — 7 уровней) и названия элементов на разных уровнях могут дублироваться, стандартный поиск превращается в проблему. Разберем, как эффективно решить эту задачу, учитывая технические ограничения «семерки».
Прежде всего, проанализируем, почему стандартные методы не позволяют решить задачу «в лоб». В 1С 7.7 существует метод НайтиПоНаименованию(), однако он имеет существенные отличия от аналогичного метода в 1С 8.х:
НайтиПоНаименованию(Название, Режим, ФлагПоиска) умеет искать либо по всему справочнику (без учета иерархии), либо строго внутри установленного родителя.НайтиПоПолномуКоду(Код, 2) позволяет найти элемент по всей цепочке через разделитель), встроенного метода НайтиПоПолномуНаименованию в платформе 7.7 не существует.Рассмотрим ситуацию подробнее: если мы просто вызовем Спр.НайтиПоНаименованию("Элемент", 0, 1), а таких элементов несколько в разных группах, система вернет первый попавшийся, что приведет к ошибке логики. Таким образом, единственный надежный путь — это последовательный спуск по иерархии.
Для поиска элемента по строке вида "Группа1/Группа2/Объект" нам необходимо реализовать алгоритм, который будет «проходить» по дереву справочника шаг за шагом. Проанализируем этот процесс по этапам:
ПолноеНаименование() 1С 7.7 всегда использует прямую косую черту "/".Спр.ИспользоватьРодителя(0) (или пустой элемент).Посмотрим на пример реализации такого поиска на языке 1С 7.7:
Функция НайтиПоПолномуНаименованию(ИмяСпр, ПолныйПуть)
Спр = СоздатьОбъект("Справочник." + ИмяСпр);
// Подготовка строки (убираем лишние пробелы)
ТекПуть = СокрЛП(ПолныйПуть);
// Используем список значений для имитации массива сегментов
СписокСегментов = СоздатьОбъект("СписокЗначений");
ВремСтр = СтрЗаменить(ТекПуть, "/", РазделительСтрок);
Для н = 1 По СтКоличествоСтрок(ВремСтр) Цикл
СписокСегментов.ДобавитьЗначение(СтрПолучитьСтроку(ВремСтр, н));
КонецЦикла;
// Начинаем поиск с корня
Спр.ИспользоватьРодителя("");
Для н = 1 По СписокСегментов.РазмерСписка() Цикл
ТекНаименование = СписокСегментов.ПолучитьЗначение(н);
// Поиск: 0 - внутри родителя, 1 - точное соответствие
Если Спр.НайтиПоНаименованию(ТекНаименование, 0, 1) = 1 Тогда
// Если это не последний сегмент, устанавливаем родителя
Если н < СписокСегментов.РазмерСписка() Тогда
Спр.ИспользоватьРодителя(Спр.ТекущийЭлемент());
КонецЕсли;
Иначе
// Если хоть один сегмент не найден - весь путь неверный
Возврат 0;
КонецЕсли;
КонецЦикла;
// Если дошли сюда, Спр.ТекущийЭлемент() - это искомый объект
Возврат Спр.ТекущийЭлемент();
КонецФункции
Выясним одну критическую особенность метода ПолноеНаименование(). Если в самом названии группы или элемента содержится символ /, платформа 1С 7.7 не экранирует его. Например, если группа называется "Склад/Магазин", а элемент внутри нее — "Товар", то полное наименование будет выглядеть так: "Склад/Магазин/Товар".
При попытке парсинга такая строка будет разбита на три части вместо двух, и поиск завершится неудачей. Важно помнить: если вы столкнулись с такой базой, программно восстановить однозначную структуру практически невозможно. В этом случае рекомендуется настаивать на выгрузке данных с использованием кодов или уникальных идентификаторов.
Если справочник содержит десятки тысяч элементов и имеет 7 уровней вложенности, последовательный поиск через НайтиПоНаименованию в цикле может работать медленно, особенно при массовой загрузке данных. Рассмотрим способы оптимизации:
ИндексированнаяТаблица (из состава FormEx или 1C++), сформировать там колонку с полным путем и проводить поиск по индексу этой колонки.ЗначениеВСтрокуВнутр(). Если вы можете повлиять на выгрузку, передавайте именно это значение. Оно содержит уникальный идентификатор объекта, который не зависит от переименований и структуры папок.Проанализируем еще несколько нюансов, которые могут повлиять на результат:
Collation сервера. Всегда лучше использовать СокрЛП() и проверять соответствие имен.ПолноеНаименование() возвращает названия как они есть. Если в конце названия группы случайно затесался пробел, визуально в дереве его не видно, но поиск по точному соответствию может его не найти, если в строке поиска его нет.НайтиПоНаименованию всегда используйте третий параметр равный 1 (поиск по точному соответствию), иначе система может найти элемент, название которого просто начинается на искомую строку.Подводя итог: штатного метода "в один клик" для поиска по полному наименованию в 1С 7.7 нет. Однако, используя последовательный перебор уровней с помощью ИспользоватьРодителя(), можно добиться корректного результата даже в сложных иерархических структурах.