Как в таблице значений заполнить колонку весом, извлеченным из названия номенклатуры

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

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

Метод 1: Посимвольный перебор строки (универсальный способ)

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

Проанализируем программный код, реализующий эту логику:


// Предположим, ТекущаяСтрока — это строка нашей Таблицы Значений на форме
ИсходнаяСтрока = ТекущаяСтрока.Номенклатура.Наименование;
ПозицияКГ = Найти(НРег(ИсходнаяСтрока), "кг");

Если ПозицияКГ > 0 Тогда
    ЧислоСтрокой = "";
    Индекс = ПозицияКГ - 1;
    РазделительНайден = Ложь;

    // Двигаемся влево от "кг" и собираем цифры
    Пока Индекс > 0 Цикл
        Символ = Сред(ИсходнаяСтрока, Индекс, 1);
        
        // Проверяем, является ли символ цифрой
        Если Найти("0123456789", Символ) > 0 Тогда
            ЧислоСтрокой = Символ + ЧислоСтрокой;
        ИначеЕсли (Символ = "." Или Символ = ",") И Не РазделительНайден Тогда
            // Обрабатываем дробную часть (только один разделитель)
            ЧислоСтрокой = Символ + ЧислоСтрокой;
            РазделительНайден = Истина;
        ИначеЕсли Не ПустаяСтрока(СокрЛП(ЧислоСтрокой)) Тогда
            // Если встретили не цифру после того, как число уже начало собираться — выходим
            Прервать;
        КонецЕсли;
        
        Индекс = Индекс - 1;
    КонецЦикла;

    // Преобразуем полученную строку в число
    Если Не ПустаяСтрока(ЧислоСтрокой) Тогда
        // Заменяем запятую на точку для корректного преобразования
        ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, ",", ".");
        ТекущаяСтрока.Вес = Число(ЧислоСтрокой);
    КонецЕсли;
КонецЕсли;

Важный нюанс: при таком подходе обязательно используйте функцию НРег() для поиска «кг», чтобы поиск не зависел от регистра (КГ, кг, Кг). Также обратите внимание на обработку пробелов между числом и единицей измерения.

Метод 2: Использование регулярных выражений (для платформы 8.3.23+)

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

Рассмотрим применение функции СтрНайтиПоРегулярномуВыражению(). Нам нужно найти последовательность цифр, за которой следует «кг». Чтобы извлечь именно число, мы можем использовать «просмотр вперед» (lookahead) в шаблоне регулярного выражения.

Пример кода для извлечения числа перед «кг»:


// Шаблон ищет цифры (включая дробные), после которых (возможно через пробел) идет "кг"
Шаблон = "\d+([,.]\d+)?(?=\s*кг)";
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(НаименованиеНоменклатуры, Шаблон, , , , Истина);

Если РезультатПоиска.Количество() > 0 Тогда
    ЗначениеВесаСтр = РезультатПоиска[0].Значение;
    ЗначениеВеса = Число(СтрЗаменить(ЗначениеВесаСтр, ",", "."));
    // Записываем результат в таблицу
    СтрокаТЗ.Вес = ЗначениеВеса;
КонецЕсли;

Преимущество этого метода заключается в его гибкости. Например, если в наименовании встречается «Вес: 25кг» или «Сахар (25.5 кг)», регулярное выражение корректно обработает оба случая без изменения программного кода.

Запись извлеченных данных в справочник

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

Посмотрим на алгоритм пакетной записи с поиском подчиненной единицы измерения:

  1. Проходим циклом по таблице значений.
  2. Для каждой номенклатуры находим нужную единицу измерения (обычно это единица для отчетов или базовая единица).
  3. Получаем объект единицы измерения, записываем вес и сохраняем изменения.

Для Каждого ТекущаяСтрока Из ТаблицаНоменклатуры Цикл
    
    Если ТекущаяСтрока.Вес = 0 Тогда
        Продолжить; // Пропускаем, если вес не был распознан
    КонецЕсли;

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

КонецЦикла;

Рекомендации по оптимизации и обработке «грязных» данных

Проанализируем ситуацию, когда данные введены небрежно. В реальной базе вы можете столкнуться со строками типа «Набор болтов 5 кг (в упаковке 100 шт)». Обычный парсер может запутаться в числах.

Рассмотрим несколько советов по улучшению алгоритма:

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

← На главную