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

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

Поиск данных в справочниках 1С по текстовому наименованию — одна из самых распространенных задач, особенно когда речь идет об импорте данных из внешних источников, таких как Excel или CSV. Однако на практике программисты часто сталкиваются с ситуацией, когда визуально одинаковые строки не позволяют найти нужный элемент. Рассмотрим детально, почему это происходит, и разберем наиболее надежные способы решения этой проблемы.

Анализируем метод НайтиПоНаименованию

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


НайденнаяДолжность = Справочники.Должности.НайтиПоНаименованию(НаименованиеДляПоиска, Истина);

Проанализируем параметры этого метода. Второй параметр — ТочноеСоответствие. Если передать значение Истина, система будет искать строгое совпадение. Если же оставить Ложь (что происходит по умолчанию), 1С найдет первый элемент, наименование которого начинается с указанной строки. Например, при поиске строки "Матрос" система может вернуть "Матрос 1 класса", что не всегда является ожидаемым результатом.

Важный момент: вопреки распространенному мнению, встроенный метод НайтиПоНаименованию в типовых конфигурациях обычно нечувствителен к регистру. То есть "матрос" и "Матрос" для него — одно и то же. Однако, как показал пример из обсуждения, причина неудачи часто кроется не в регистре, а в «невидимых» символах.

Скрытые символы: главные враги поиска

Разберем ситуацию, с которой столкнулся автор: в конце наименования стояла точка, которую не было видно при беглом просмотре. Помимо знаков препинания, существуют и другие «коварные» символы:

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


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

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

Рассмотрим более гибкий вариант поиска — использование языка запросов 1С. Запросы позволяют не только искать по наименованию, но и делать это массово, что значительно ускоряет работу программы при загрузке больших списков.

Оператор ПОДОБНО позволяет выполнять поиск без учета регистра (в зависимости от настроек SQL-сервера) и с использованием спецсимволов. Посмотрим на пример кода:


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

Запрос.УстановитьПараметр("Наименование", СокрЛП(СтрокаПоиска));
Результат = Запрос.Выполнить();

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

Нормализация данных и работа с регистром

В некоторых случаях, если база данных настроена как Case-Sensitive (чувствительная к регистру на уровне SQL), стандартный поиск может давать сбои. Чтобы этого избежать, профессиональным подходом считается нормализация. Мы можем привести обе строки (и в базе, и в поиске) к верхнему регистру.

Проанализируем совет из обсуждения: разобрать строку и собрать её заново в одном регистре. На практике это выглядит так:


// Приведение к единому регистру для гарантированного сравнения
Если ВРег(НаименованиеИзБазы) = ВРег(НаименованиеПоиска) Тогда
    // Элемент найден
КонецЕсли;

Радикальное решение: регулярные выражения

Если данные в файле-источнике совсем «грязные», мы можем применить очистку через регулярные выражения. Это позволит оставить в строке только буквы и цифры, удалив все точки, запятые и скрытые управляющие символы.


RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина;
RegExp.Global = Истина;
RegExp.Pattern = "[^а-яА-ЯёЁa-zA-Z0-9 ]"; // Удаляем всё, кроме букв, цифр и пробела
РезультатОчистки = RegExp.Replace(СтрокаИзФайла, "");

Рекомендации по производительности

Выясним, какой способ поиска быстрее. Метод НайтиПоНаименованию хорош для единичных операций. Но если вы загружаете справочник из 10 000 строк Excel, выполнять 10 000 раз метод НайтиПоНаименованию — плохая практика.

Разберем оптимальный алгоритм массовой загрузки:

  1. Выгружаем все существующие наименования из справочника 1С в индексированную ТаблицуЗначений или в Соответствие.
  2. При чтении каждой строки из Excel обращаемся к этой таблице в памяти.
  3. Это сокращает количество обращений к базе данных до одного (в самом начале), что ускоряет процесс в десятки раз.

Важное предостережение: Поиск по наименованию всегда несет в себе риск дублей или неверных сопоставлений. Если есть возможность, всегда старайтесь использовать поиск по уникальным идентификаторам (GUID), кодам или артикулам, так как это гарантирует 100% точность результата.

← На главную