Почему метод НайтиПоНаименованию в 1С не находит элемент при загрузке данных из Excel?

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

При разработке обработок загрузки данных из внешних источников (в частности, Microsoft Excel) разработчики нередко сталкиваются с ситуацией, когда метод НайтиПоНаименованию() возвращает пустую ссылку, хотя визуально строка поиска полностью совпадает с наименованием элемента в базе. Разберем причины такого поведения платформы, способы диагностики и правила корректной подготовки данных.

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

Рассмотрим синтаксис и поведение стандартного метода поиска по наименованию менеджера справочника:


// Синтаксис метода:
// НайтиПоНаименованию(<Наименование>, <ТочноеСоответствие>, <Родитель>, <Владелец>)
ФизЛицо = Справочники.ФизическиеЛица.НайтиПоНаименованию(ФИО, Истина);

Если параметр ТочноеСоответствие установлен в значение Истина, платформа выполняет поиск строки с полным совпадением (за исключением концевых пробелов). Если совпадений не найдено, метод возвращает пустую ссылку соответствующего типа (СправочникСсылка.ФизическиеЛица.ПустаяСсылка()), а если наименование в метаданных справочника имеет нулевую длину — значение Неопределено.

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

  1. Неразрывные пробелы (код ASCII 160, Unicode U+00A0). В файлах Excel вместо стандартного пробела (код 32) часто содержатся неразрывные пробелы (в 1С представлены константой Символы.НПП). Для СУБД символы с кодами 32 и 160 являются абсолютно разными.
  2. Смешанная раскладка (латиница и кириллица). Буквы «С», «О», «Р», «А», «Е», «Х» визуально идентичны в русском и английском алфавитах, но имеют разные коды символов.
  3. Повторяющиеся и управляющие пробельные символы. Лишние двойные пробелы между словами, знаки табуляции (Символы.Таб), мягкие переносы или невидимые служебные символы.
  4. Превышение длины реквизита. Если строка в файле длиннее допустимой длины реквизита Наименование, заданного в конфигураторе.

Решение 1. Очистка и нормализация строки поиска

Проанализируем базовый способ устранения неразрывных пробелов. Чтобы метод нашел элемент, необходимо заменить все неразрывные пробелы на стандартные с помощью функции СтрЗаменить(), а также удалить лишние пробелы по краям с помощью СокрЛП():


// Очистка от неразрывных пробелов и крайних пробелов
ФИО = СокрЛП(СтрЗаменить(ФИО, Символы.НПП, " "));

// Выполняем поиск
СсылкаНаФизЛицо = Справочники.ФизическиеЛица.НайтиПоНаименованию(ФИО, Истина);
Если Не СсылкаНаФизЛицо.Пустая() Тогда
    // Элемент успешно найден
КонецЕсли;

Для гарантированной очистки строк от любых скрытых символов и двойных пробелов применим комплексную функцию предварительной обработки:


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

Решение 2. Поиск по частичному совпадению

Если в наименовании могут присутствовать расхождения в инициалах или окончаниях, мы можем отключить параметр точного соответствия. При значении параметра ТочноеСоответствие = Ложь платформа выполняет поиск по совпадению с начала строки (по левой части):


// Поиск по началу наименования
ФИО = НормализоватьСтрокуПоиска(ФИО);
СсылкаНаФизЛицо = Справочники.ФизическиеЛица.НайтиПоНаименованию(ФИО, Ложь);

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

Решение 3. Оптимизация: пакетный поиск через запрос вместо цикла

Вызов НайтиПоНаименованию() внутри цикла обработки строк Excel создает проблему производительности (антипаттерн N+1 запросов к базе данных). При тысячах строк процесс загрузки будет выполняться крайне медленно.

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


// 1. Формируем таблицу значений с данными из Excel
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("НомерСтрокиФайла", Новый ОписаниеТипов("Число"));
ТаблицаДанных.Колонки.Добавить("ФИО", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(150)));
ТаблицаДанных.Колонки.Добавить("Телефон", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(50)));

// Заполняем таблицу данными с предварительной нормализацией
Для Каждого СтрокаФайла Из МассивДанныхФайла Цикл
    НоваяСтрока = ТаблицаДанных.Добавить();
    НоваяСтрока.НомерСтрокиФайла = СтрокаФайла.Номер;
    НоваяСтрока.ФИО = НормализоватьСтрокуПоиска(СтрокаФайла.ФИО);
    НоваяСтрока.Телефон = СтрокаФайла.Телефон;
КонецЦикла;

// 2. Выполняем пакетное сопоставление через запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТаблицаДанных.НомерСтрокиФайла КАК НомерСтрокиФайла,
    |	ТаблицаДанных.ФИО КАК ФИО_Поиск,
    |	ТаблицаДанных.Телефон КАК Телефон,
    |	ФизическиеЛица.Ссылка КАК СсылкаНаФизЛицо
    |ИЗ
    |	&ТаблицаДанных КАК ТаблицаДанных
    |		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК ФизическиеЛица
    |		ПО (ТаблицаДанных.ФИО = ФизическиеЛица.Наименование)
    |			И (НЕ ФизическиеЛица.ПометкаУдаления)";

Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

// 3. Обрабатываем полученный результат
Для Каждого Стр Из РезультатЗапроса Цикл
    Если ЗначениеЗаполнено(Стр.СсылкаНаФизЛицо) Тогда
        // Элемент найден в базе - выполняем запись телефона
    Иначе
        // Элемент не найден - логируем ошибку или создаем новый элемент
    КонецЕсли;
КонецЦикла;

Рекомендации по сопоставлению физических лиц

  1. Используйте уникальные идентификаторы. Поиск физических лиц исключительно по строке ФИО ненадежен из-за возможных полных тезок и смены фамилий. При наличии возможности сопоставляйте записи по ИНН или СНИЛС.
  2. Учитывайте структуру конфигурации. В типовых конфигурациях (например, «1С:Бухгалтерия предприятия 3.0») ФИО физических лиц хранится не только в наименовании, но и в специализированном регистре сведений с историей изменений ФИО. При сложном поиске целесообразно выполнять соединение с последним срезом этого регистра.
← На главную