В практике разработчика 1С часто возникает задача извлечения структурированных данных из неструктурированных текстовых полей. Типичный пример — получение веса товара из его наименования, когда данные загружаются из внешних прайс-листов или весов. В этой статье мы подробно разберем несколько методов решения этой задачи: от простых строковых функций до использования регулярных выражений и инструментов Библиотеки стандартных подсистем (БСП).
Самый очевидный способ — найти вхождение единицы измерения (например, "кг") и проанализировать текст, стоящий слева от этой метки. Рассмотрим алгоритм, который ищет позицию "кг" с конца строки, так как вес обычно указывается в конце наименования.
Разберем логику по шагам:
СтрНайти с параметром НаправлениеПоиска.СКонца.Число.Проанализируем пример кода, реализующий этот подход:
// Исходная строка: "Шок. Конфеты Твикс минис соленая карамель 2,7кг"
Поз = СтрНайти(СтрокаСКг, "кг", НаправлениеПоиска.СКонца);
Если Поз = 0 Тогда
ВесКг = 0;
Иначе
// Получаем часть строки до "кг"
СтрокаБезКг = Лев(СтрокаСКг, Поз - 1);
// Ищем пробел перед числом
ПозПробела = СтрНайти(СтрокаБезКг, " ", НаправлениеПоиска.СКонца);
Если ПозПробела = 0 Тогда
СтрокаЧисла = СтрокаБезКг;
Иначе
СтрокаЧисла = Сред(СтрокаБезКг, ПозПробела + 1);
КонецЕсли;
// Очищаем от возможных лишних знаков и преобразуем
Попытка
ВесКг = Число(СтрЗаменить(СтрокаЧисла, ",", "."));
Исключение
ВесКг = 0;
КонецПопытки;
КонецЕсли;
Важный нюанс: Функция Число() в 1С чувствительна к системным настройкам разделителя (точка или запятая). Поэтому перед преобразованием всегда рекомендуется использовать СтрЗаменить, чтобы привести разделитель к ожидаемому виду.
Предыдущий метод может давать сбои, если между числом и "кг" нет пробела или если в строке присутствуют скобки. Более надежный подход — просканировать строку и собрать все символы, которые могут относиться к числу (цифры, точки, запятые).
Рассмотрим реализацию через массив допустимых символов. Этот алгоритм позволяет "выцепить" число, даже если оно окружено спецсимволами.
МассивИскомыхСимволов = СтрРазделить("0123456789,.", "");
ИсходнаяСтрока = "Славянка 2,5кг/1 (шт.)";
НайденноеЧислоСтр = "";
ВесНаден = Ложь;
// Ищем вхождение "кг" для ограничения области поиска
ПозКг = СтрНайти(НРег(ИсходнаяСтрока), "кг", НаправлениеПоиска.СКонца);
Если ПозКг > 0 Тогда
// Идем от символа перед "кг" влево
Для Счетчик = -(ПозКг-1) По -1 Цикл
ТекСимвол = Сред(ИсходнаяСтрока, -Счетчик, 1);
Если МассивИскомыхСимволов.Найти(ТекСимвол) <> Неопределено Тогда
НайденноеЧислоСтр = ТекСимвол + НайденноеЧислоСтр;
ВесНаден = Истина;
ИначеЕсли ВесНаден Тогда
// Если уже начали собирать число и встретили не цифру - значит, число закончилось
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Результат = Число(СтрЗаменить(НайденноеЧислоСтр, ",", "."));
Проанализируем наиболее современный и эффективный способ разбора строк — регулярные выражения. В 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кг"
ЧистоеЧисло = СтрЗаменить(НРег(ПоследнееСлово), "кг", "");
Вес = Число(СтрЗаменить(ЧистоеЧисло, ",", "."));
При работе с текстовым разбором мы часто сталкиваемся с проблемами, которые не видны на первый взгляд:
СтрЗаменить(Текст, Символы.НПП, " ").НРег() перед поиском.Как справедливо отмечают эксперты, семантический разбор строк — это крайняя мера. Буквы в наименовании не предназначены для надежного хранения информации. Если ваша система предполагает регулярную работу с весом (для логистики, этикеток или отчетности), правильнее всего:
Выясним причину популярности таких задач: обычно это плохая гигиена данных на входе. Автоматизировав процесс извлечения один раз, вы сэкономите массу времени пользователям, но всегда стремитесь к тому, чтобы данные хранились в предназначенных для этого полях.