Как извлечь числовое значение веса из текстовой строки наименования в 1С

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

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

Метод 1: Поиск по ключевым символам и позиционирование

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

Разберем логику по шагам:

  1. Используем функцию СтрНайти с параметром НаправлениеПоиска.СКонца.
  2. Отсекаем правую часть строки вместе с "кг".
  3. Ищем ближайший пробел слева от найденной позиции, чтобы определить начало числа.
  4. Выделяем подстроку и преобразуем ее в тип Число.

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


// Исходная строка: "Шок. Конфеты Твикс минис соленая карамель 2,7кг"
Поз = СтрНайти(СтрокаСКг, "кг", НаправлениеПоиска.СКонца);
Если Поз = 0 Тогда
    ВесКг = 0;
Иначе
    // Получаем часть строки до "кг"
    СтрокаБезКг = Лев(СтрокаСКг, Поз - 1);
    
    // Ищем пробел перед числом
    ПозПробела = СтрНайти(СтрокаБезКг, " ", НаправлениеПоиска.СКонца);
    
    Если ПозПробела = 0 Тогда
        СтрокаЧисла = СтрокаБезКг;
    Иначе
        СтрокаЧисла = Сред(СтрокаБезКг, ПозПробела + 1);
    КонецЕсли;
    
    // Очищаем от возможных лишних знаков и преобразуем
    Попытка
        ВесКг = Число(СтрЗаменить(СтрокаЧисла, ",", "."));
    Исключение
        ВесКг = 0;
    КонецПопытки;
КонецЕсли;

Важный нюанс: Функция Число() в 1С чувствительна к системным настройкам разделителя (точка или запятая). Поэтому перед преобразованием всегда рекомендуется использовать СтрЗаменить, чтобы привести разделитель к ожидаемому виду.

Метод 2: Универсальный перебор символов (Фильтрация)

Предыдущий метод может давать сбои, если между числом и "кг" нет пробела или если в строке присутствуют скобки. Более надежный подход — просканировать строку и собрать все символы, которые могут относиться к числу (цифры, точки, запятые).

Рассмотрим реализацию через массив допустимых символов. Этот алгоритм позволяет "выцепить" число, даже если оно окружено спецсимволами.


МассивИскомыхСимволов = СтрРазделить("0123456789,.", ""); 
ИсходнаяСтрока = "Славянка 2,5кг/1 (шт.)";
НайденноеЧислоСтр = "";
ВесНаден = Ложь;

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

Результат = Число(СтрЗаменить(НайденноеЧислоСтр, ",", "."));

Метод 3: Использование регулярных выражений (RegEx)

Проанализируем наиболее современный и эффективный способ разбора строк — регулярные выражения. В 1С они доступны через COM-объект VBScript.RegExp. Этот метод позволяет одной строкой кода задать сложный шаблон поиска.

Для нашей задачи идеально подойдет паттерн (\d+[\.,]?\d*)\s*кг. Он означает: найти группу цифр, за которой может следовать точка или запятая и еще группа цифр, после которых (возможно через пробел) идет текст "кг".

Посмотрим на пример функции:


Функция ИзвлечьВесИзСтроки(Знач ВхТекст) Экспорт
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина;
    RegExp.Global = Ложь;
    RegExp.Pattern = "(\d+[\.,]?\d*)\s*кг";
    
    Matches = RegExp.Execute(ВхТекст);
    Если Matches.Count > 0 Тогда
        РезультатСтр = Matches.Item(0).SubMatches.Item(0);
        Возврат Число(СтрЗаменить(РезультатСтр, ",", "."));
    КонецЕсли;
    
    Возврат 0;
КонецФункции

Преимущества RegEx: гибкость и устойчивость к изменению формата строки. Если завтра поставщик напишет "вес 2.7 кг" или "2,7кг.", регулярное выражение продолжит работать корректно.

Использование функций БСП

Если вы работаете в современной конфигурации (УТ 11, ERP, БП 3.0), обязательно загляните в общий модуль СтроковыеФункцииКлиентСервер. В нем реализовано множество полезных инструментов, которые избавят вас от написания велосипедов.

Например, функция РазложитьСтрокуВМассивПодстрок() позволяет быстро разбить наименование по набору разделителей (пробелы, скобки, слеши) и проанализировать последний элемент массива.


// Пример использования БСП
МассивСлов = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Наименование, " ");
ПоследнееСлово = МассивСлов[МассивСлов.Количество() - 1]; // Например, "2,7кг"
ЧистоеЧисло = СтрЗаменить(НРег(ПоследнееСлово), "кг", "");
Вес = Число(СтрЗаменить(ЧистоеЧисло, ",", "."));

Типичные ошибки и подводные камни

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

Архитектурный совет

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

  1. Создать отдельный числовой реквизит "Вес" в справочнике Номенклатура.
  2. Выполнить разбор строки один раз при загрузке данных.
  3. В дальнейшем обращаться только к числовому реквизиту, что исключит ошибки и ускорит работу системы.

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

← На главную