Как реализовать поиск похожих артикулов и контроль дублей в 1С, игнорируя знаки препинания?

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

В процессе ведения справочника Номенклатура пользователи часто сталкиваются с проблемой появления дублей из-за разного написания артикулов. Один и тот же товар может быть записан как "NPort 5110-T", "NPort5110T" или "NPort 5110/T". Стандартная проверка на уникальность в 1С не справляется с такими случаями, так как для платформы это разные строки. В этой статье мы подробно разберем, как реализовать эффективную систему контроля ввода артикулов, которая будет игнорировать знаки препинания, пробелы и другие спецсимволы.

Метод 1: Создание нормализованного реквизита для поиска

Проанализируем наиболее эффективный с точки зрения производительности подход. Использование оператора ПОДОБНО в запросах при каждом вводе артикула — не лучшее решение. На больших базах (от 50-100 тысяч записей) такой поиск будет выполняться крайне медленно, так как система не сможет эффективно использовать индексы. Вместо этого мы создадим специальный служебный реквизит.

Разберем реализацию по шагам:

  1. Добавление реквизита: В справочнике Номенклатура создадим новый реквизит, например, АртикулДляПоиска.
  2. Тип данных: Строка, длина должна соответствовать основному артикулу.
  3. Индексация: Это критически важный момент. Установите свойство Индексировать (или "Индексировать с дополнительным упорядочиванием"). Это позволит мгновенно находить дубли запросом по равенству.
  4. Ограничение доступа: Этот реквизит не нужно выводить на форму для пользователя, он должен заполняться программно.

Метод 2: Программная нормализация строки

Теперь выясним, как правильно "очистить" артикул перед сохранением. Нам нужно удалить все знаки препинания: пробелы, кавычки, скобки, дефисы, слеши, точки и так далее. Рассмотрим пример функции, которую можно разместить в общем модуле для использования во всей конфигурации.


Функция ПолучитьНормализованныйАртикул(Знач ИсходныйАртикул) Экспорт
    
    // Переводим в верхний регистр для исключения влияния регистра
    Результат = ВРег(ИсходныйАртикул);
    
    // Список символов для удаления
    СимволыДляЗамены = " ""'()-\|/*+,;#.";
    
    Для НомерСимвола = 1 По СтрДлина(СимволыДляЗамены) Цикл
        Символ = Сред(СимволыДляЗамены, НомерСимвола, 1);
        Результат = СтрЗаменить(Результат, Символ, "");
    КонецЦикла;
    
    // Дополнительно можно удалить непечатные символы
    Результат = СтрЗаменить(Результат, Симв(160), ""); // Неразрывный пробел
    
    Возврат Результат;
    
КонецФункции

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


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

Метод 3: Обработка визуально схожих символов (Омографы)

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


// Пример замены схожих символов
СтрКириллица = "АВЕКМНОРСТУХ"; 
СтрЛатиница  = "ABEKMHOPCTYX";

Для и = 1 По СтрДлина(СтрКириллица) Цикл
    СимволКир = Сред(СтрКириллица, и, 1);
    СимволЛат = Сред(СтрЛатиница, и, 1);
    Результат = СтрЗаменить(Результат, СимволКир, СимволЛат);
КонецЦикла;

Интеграция контроля в логику системы

Посмотрим на пример реализации проверки в модуле объекта справочника Номенклатура. Мы будем использовать событие ПередЗаписью, чтобы предотвратить запись дубля в базу данных.


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

Дополнительные рекомендации по улучшению UX

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

Важный момент: всегда используйте индексацию служебного поля. Без индекса запрос по 92 тысячам записей приведет к полному сканированию таблицы (Table Scan), что создаст значительную нагрузку на SQL-сервер при одновременной работе многих пользователей.

← На главную