В процессе автоматизации ведения нормативно-справочной информации (НСИ) часто возникает задача «разбора» наименований. Представим ситуацию: в справочнике Номенклатура накоплено множество позиций, где вес указан прямо в названии (например, «Мука пшеничная 25 кг»), но соответствующий реквизит Вес в единицах измерения не заполнен. Разберем подробно, как программно извлечь эти данные, заполнить ими таблицу значений и перенести информацию в базу данных.
Этот подход полезен, если вы работаете на старых версиях платформы или хотите полностью контролировать логику обхода каждого символа. Рассмотрим алгоритм, который ищет вхождение подстроки «кг» и извлекает число, стоящее слева от нее.
Проанализируем программный код, реализующий эту логику:
// Предположим, ТекущаяСтрока — это строка нашей Таблицы Значений на форме
ИсходнаяСтрока = ТекущаяСтрока.Номенклатура.Наименование;
ПозицияКГ = Найти(НРег(ИсходнаяСтрока), "кг");
Если ПозицияКГ > 0 Тогда
ЧислоСтрокой = "";
Индекс = ПозицияКГ - 1;
РазделительНайден = Ложь;
// Двигаемся влево от "кг" и собираем цифры
Пока Индекс > 0 Цикл
Символ = Сред(ИсходнаяСтрока, Индекс, 1);
// Проверяем, является ли символ цифрой
Если Найти("0123456789", Символ) > 0 Тогда
ЧислоСтрокой = Символ + ЧислоСтрокой;
ИначеЕсли (Символ = "." Или Символ = ",") И Не РазделительНайден Тогда
// Обрабатываем дробную часть (только один разделитель)
ЧислоСтрокой = Символ + ЧислоСтрокой;
РазделительНайден = Истина;
ИначеЕсли Не ПустаяСтрока(СокрЛП(ЧислоСтрокой)) Тогда
// Если встретили не цифру после того, как число уже начало собираться — выходим
Прервать;
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
// Преобразуем полученную строку в число
Если Не ПустаяСтрока(ЧислоСтрокой) Тогда
// Заменяем запятую на точку для корректного преобразования
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, ",", ".");
ТекущаяСтрока.Вес = Число(ЧислоСтрокой);
КонецЕсли;
КонецЕсли;
Важный нюанс: при таком подходе обязательно используйте функцию НРег() для поиска «кг», чтобы поиск не зависел от регистра (КГ, кг, Кг). Также обратите внимание на обработку пробелов между числом и единицей измерения.
Если ваша информационная база работает на современной платформе (версии 8.3.23 и выше), задачу можно решить гораздо элегантнее с помощью встроенных функций работы с регулярными выражениями. Это позволяет избежать громоздких циклов и сложной логики проверок.
Рассмотрим применение функции СтрНайтиПоРегулярномуВыражению(). Нам нужно найти последовательность цифр, за которой следует «кг». Чтобы извлечь именно число, мы можем использовать «просмотр вперед» (lookahead) в шаблоне регулярного выражения.
Пример кода для извлечения числа перед «кг»:
// Шаблон ищет цифры (включая дробные), после которых (возможно через пробел) идет "кг"
Шаблон = "\d+([,.]\d+)?(?=\s*кг)";
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(НаименованиеНоменклатуры, Шаблон, , , , Истина);
Если РезультатПоиска.Количество() > 0 Тогда
ЗначениеВесаСтр = РезультатПоиска[0].Значение;
ЗначениеВеса = Число(СтрЗаменить(ЗначениеВесаСтр, ",", "."));
// Записываем результат в таблицу
СтрокаТЗ.Вес = ЗначениеВеса;
КонецЕсли;
Преимущество этого метода заключается в его гибкости. Например, если в наименовании встречается «Вес: 25кг» или «Сахар (25.5 кг)», регулярное выражение корректно обработает оба случая без изменения программного кода.
После того как колонка Вес в нашей таблице значений заполнена, необходимо перенести эти данные в базу. Выясним причину, почему запись каждой строки по отдельности может быть неэффективной: при работе с тысячами позиций это создаст избыточную нагрузку на сервер и СУБД.
Посмотрим на алгоритм пакетной записи с поиском подчиненной единицы измерения:
Для Каждого ТекущаяСтрока Из ТаблицаНоменклатуры Цикл
Если ТекущаяСтрока.Вес = 0 Тогда
Продолжить; // Пропускаем, если вес не был распознан
КонецЕсли;
// Ищем единицу измерения, где владельцем является наша номенклатура
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
|ГДЕ
| ЕдиницыИзмерения.Владелец = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", ТекущаяСтрока.Номенклатура);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
ОбъектЕдиницы = Выборка.Ссылка.ПолучитьОбъект();
ОбъектЕдиницы.Вес = ТекущаяСтрока.Вес;
Попытка
ОбъектЕдиницы.Записать();
Исключение
Сообщить("Не удалось записать вес для " + ТекущаяСтрока.Номенклатура);
КонецПопытки;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Проанализируем ситуацию, когда данные введены небрежно. В реальной базе вы можете столкнуться со строками типа «Набор болтов 5 кг (в упаковке 100 шт)». Обычный парсер может запутаться в числах.
Рассмотрим несколько советов по улучшению алгоритма:
Вес должны быть приведены к единому стандарту (обычно к килограммам). Например, если нашли «г», разделите результат на 1000.СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов. Это поможет очистить строку от спецсимволов перед анализом.Таким образом, мы разобрали комплексный подход к извлечению числовых данных из строк. Использование регулярных выражений является наиболее современным и надежным методом, в то время как посимвольный перебор остается надежным инструментом для простых задач на любых версиях 1С:Предприятия.