Как эффективно искать в строке по списку значений и правильно передавать дополнительные параметры в обработку заполнения в 1С?

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

В процессе разработки в среде 1С:Предприятие программисты регулярно сталкиваются с двумя классическими задачами. Первая — это проверка наличия ключевых слов или фраз в текстовой строке по заданному списку. Вторая — корректная передача контекстных данных при создании новых объектов, чтобы процедура ОбработкаЗаполнения в модуле объекта могла получить специфические флаги (например, признак копирования или специальный режим заполнения). В этой статье мы подробно разберем обе задачи, рассмотрим лучшие практики платформы 1С v8.3 и найдем наиболее изящные архитектурные решения.

Часть 1. Поиск в строке по списку значений: от простых циклов до регулярных выражений

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

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

Способ 1. Простой перебор списка с использованием СтрНайти()

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


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

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

Способ 2. Использование регулярных выражений (VBScript.RegExp)

Если перед нами стоит задача производительного поиска, или когда список значений исчисляется сотнями элементов, стандартный перебор в цикле может замедлить работу системы. В этом случае мы можем прибегнуть к возможностям операционной системы Windows и использовать COM-объект регулярных выражений.

Сформируем регулярное выражение, объединив все элементы списка символом вертикальной черты |, который в синтаксисе регулярных выражений означает логическое "ИЛИ". Проанализируем пример кода:


Функция СодержитЗначениеРегулярноеВыражение(ИсходныйТекст, СписокКлючевыхСлов) Экспорт
    
    // Создаем COM-объект для работы с регулярными выражениями
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина; // Игнорировать регистр символов
    RegExp.Global = Ложь;       // Нам достаточно найти хотя бы одно совпадение
    
    // Формируем паттерн вида (значение1|значение2|значение3)
    МассивЗначений = Новый Массив;
    Для Каждого ЭлементСписка Из СписокКлючевыхСлов Цикл
        МассивЗначений.Добавить(ЭлементСписка.Значение);
    КонецЦикла;
    
    ШаблонПоиска = СтрСоединить(МассивЗначений, "|");
    RegExp.Pattern = "(" + ШаблонПоиска + ")";
    
    // Выполняем тест на соответствие строки шаблону
    Возврат RegExp.Test(ИсходныйТекст);
    
КонецФункции

Этот метод работает значительно быстрее на больших массивах данных, так как сам поиск выполняется оптимизированным движком регулярных выражений на уровне операционной системы, минуя интерпретатор кода 1С на каждой итерации цикла.

Способ 3. Поиск точных совпадений через СтрРазделить()

Иногда нам нужно найти не просто вхождение подстроки (например, внутри слова), а именно отдельное целое слово из списка. В такой ситуации стандартный метод СтрНайти() может вернуть ложноположительный результат. Чтобы избежать этого, мы можем разделить исходную строку на массив слов по символам-разделителям (пробелы, знаки препинания) и быстро проверить вхождение элементов.


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

Этот способ гарантирует, что мы не найдем слово "под" внутри слова "подушка", если в нашем списке значений было только слово "под".

Часть 2. Передача параметров в ОбработкаЗаполнения: решаем проблему потери флагов

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

Вы хотите программно открыть форму нового элемента справочника или документа и передать туда не только ссылку-основание, но и дополнительный служебный параметр (например, флаг Копирование = Истина), чтобы использовать его внутри события ОбработкаЗаполнения в модуле создаваемого объекта.

Если вы попытаетесь передать параметр напрямую в структуру параметров формы, например так:


ПараметрыФормы = Новый Структура("Основание", ТекущаяСтрока);
ПараметрыФормы.Вставить("Копирование", Истина);
ОткрытьФорму("Справочник.Товары.Форма.ФормаЭлемента", ПараметрыФормы);

то обнаружите, что в модуле объекта внутри предопределенной процедуры ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) в параметре ДанныеЗаполнения окажется исключительно ссылка ТекущаяСтрока. Ваш дополнительный параметр Копирование просто потеряется, так как платформа по умолчанию передает в качестве данных заполнения только значение ключа "Основание".

Элегантное решение: Вложенная структура в качестве основания

Для того чтобы обойти это ограничение платформы и пробросить любые произвольные данные в модуль объекта, мы должны передать в качестве параметра "Основание" не просто ссылку, а вложенную структуру, содержащую как саму ссылку на исходный объект, так и все необходимые нам сопутствующие флаги.

Выясним, как это выглядит на практике. Разберем код вызова формы:


// Формируем вложенную структуру данных, которую мы хотим передать
ДанныеОснования = Новый Структура;
ДанныеОснования.Вставить("СсылкаНаОбъект", ТекущаяСтрока);
ДанныеОснования.Вставить("Копирование", Истина);
ДанныеОснования.Вставить("СлужебныйПараметр", "ЗначениеСлужебногоПараметра");

// Помещаем эту структуру в параметр "Основание" передаваемой формы
ПараметрыФормы = Новый Структура("Основание", ДанныеОснования);

// Открываем форму нового элемента
ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаЭлемента", ПараметрыФормы);

При таком подходе платформа передаст всю структуру ДанныеОснования целиком в модуль объекта. Теперь посмотрим, как правильно и безопасно обработать эти данные на стороне модуля объекта в процедуре ОбработкаЗаполнения.


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    // Проверяем тип пришедших данных заполнения
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
        
        // Извлекаем основную ссылку-оригинал для заполнения реквизитов
        СсылкаНаОснование = Неопределено;
        ДанныеЗаполнения.Свойство("СсылкаНаОбъект", СсылкаНаОснование);
        
        Если ЗначениеЗаполнено(СсылкаНаОснование) Тогда
            // Выполняем стандартное заполнение реквизитов из объекта-источника
            ЗаполнитьПоОснованию(СсылкаНаОснование);
        КонецЕсли;
        
        // Считываем наши дополнительные флаги и параметры
        ФлагКопирования = Ложь;
        Если ДанныеЗаполнения.Свойство("Копирование", ФлагКопирования) И ФлагКопирования Тогда
            // Реализуем особую логику, если объект создается путем копирования
            ЭтотОбъект.Комментарий = "Создано копированием на основании: " + Строка(СсылкаНаОснование);
        КонецЕсли;
        
    ИначеЕсли ТипЗнч(ДанныеЗаполнения) = Тип("СправочникСсылка.Номенклатура") Тогда
        
        // Обычный сценарий ввода на основании, когда передана чистая ссылка
        ЗаполнитьПоОснованию(ДанныеЗаполнения);
        
    КонецЕсли;
    
КонецПроцедуры

Используя метод структуры Свойство(), мы обеспечиваем высокую отказоустойчивость кода. Если в процедуру придет обычная ссылка (например, при стандартном вводе на основании средствами платформы), сработает ветка ИначеЕсли, и логика заполнения не нарушится.

Альтернативные сценарии: Параметр "ЗначенияЗаполнения" и "ДополнительныеСвойства"

В зависимости от архитектурных задач проекта, вам могут подойти и другие встроенные механизмы 1С.

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

Таким образом, мы детально разобрали, как оптимизировать текстовый поиск по спискам значений, и научились гибко управлять заполнением объектов, используя механизмы вложенных структур в параметрах управляемых форм 1С.

← На главную