Как извлечь и сложить целые и дробные числа из строки в 1С без регулярных выражений?

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

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

Анализ проблемы и постановка логики

Рассмотрим пример строки: dsfhs12.432.234.32sdfsdf21.434dsfsd4.34. Наша задача — не просто вытащить цифры, но и правильно интерпретировать точки. Согласно условию денежного формата:

  1. Если после точки идет ровно два знака (например, .32 или .34), то эта точка является десятичным разделителем.
  2. Если после точки идет любое другое количество знаков (например, три знака в .434), то точка считается разделителем групп разрядов и должна быть проигнорирована при формировании итогового числа.

Разберем, как реализовать это пошагово.

Решение 1: Последовательный перебор символов и анализ подстрок

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

Рассмотрим код функции, которая выполняет первичный сбор числовых блоков:


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

Теперь проанализируем вспомогательную процедуру ОбработатьИДобавитьЧисло, которая отделяет копейки от целой части:


Процедура ОбработатьИДобавитьЧисло(СтрокаБлока, МассивРезультатов)
    // Разделяем блок на части по точке
    Части = СтрРазделить(СтрокаБлока, ".", Ложь);
    КолЧастей = Части.Количество();
    
    Если КолЧастей = 0 Тогда Возврат; КонецЕсли;
    
    ПоследняяЧасть = Части[КолЧастей - 1];
    ДробнаяЧасть = "";
    ЦелаяЧасть = "";
    
    // Основная логика: если в хвосте ровно 2 цифры - это копейки
    Если КолЧастей > 1 И СтрДлина(ПоследняяЧасть) = 2 Тогда
        ДробнаяЧасть = ПоследняяЧасть;
        Для и = 0 По КолЧастей - 2 Цикл
            ЦелаяЧасть = ЦелаяЧасть + Части[и];
        КонецЦикла;
    Иначе
        // Все части соединяем в одну целую строку
        Для Каждого Часть Из Части Цикл
            ЦелаяЧасть = ЦелаяЧасть + Часть;
        КонецЦикла;
    КонецЕсли;
    
    // Преобразуем в числовой тип 1С
    Если ПустаяСтрока(ЦелаяЧасть) Тогда ЦелаяЧасть = "0"; КонецЕсли;
    
    СтрокаДляКонвертации = ЦелаяЧасть + ?(ДробнаяЧасть <> "", "." + ДробнаяЧасть, "");
    
    Попытка
        // Важно: Число() может зависеть от региональных настроек (точка/запятая)
        Результат = Число(СтрЗаменить(СтрокаДляКонвертации, ".", 
                    Лево(Формат(1.1, "ЧРД=."), 1)));
        МассивРезультатов.Добавить(Результат);
    Исключение
        // Ошибка конвертации
    КонецПопытки;
КонецПроцедуры

Решение 2: Оптимизированный разбор через СтрРазделить

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


Функция ИзвлечьЧислаБыстро(ИсходнаяСтрока)
    ТипЧисло = Новый ОписаниеТипов("Число", 15, 2);
    // Определяем все символы, которые НЕ являются цифрами или точкой
    Разделители = ИсходнаяСтрока;
    Для и = 0 По 9 Цикл
        Разделители = СтрЗаменить(Разделители, Формат(и, "ЧГ=0"), "");
    КонецЦикла;
    Разделители = СтрЗаменить(Разделители, ".", "");
    
    // Получаем массив строк, где остались только цифры и точки
    НаборЧисел = СтрРазделить(ИсходнаяСтрока, Разделители, Ложь);
    
    ИтоговыйМассив = Новый Массив;
    
    Для Каждого СтрокаЧисла Из НаборЧисел Цикл
        Части = СтрРазделить(СтрокаЧисла, ".", Ложь);
        ИндексПоследней = Части.ВГраница();
        
        Если ИндексПоследней > 0 И СтрДлина(Части[ИндексПоследней]) = 2 Тогда
            Копейки = Части[ИндексПоследней];
            Части.Удалить(ИндексПоследней);
            Целое = СтрСоединить(Части, "");
        Иначе
            Копейки = "0";
            Целое = СтрСоединить(Части, "");
        КонецЕсли;
        
        Значение = Число(Целое) + Число(Копейки) / 100;
        ИтоговыйМассив.Добавить(Значение);
    КонецЦикла;
    
    Возврат ИтоговыйМассив;
КонецФункции

Важные нюансы обработки данных

При работе с суммами и денежными форматами в 1С следует учитывать несколько критических моментов, которые мы выяснили в ходе анализа:

Суммирование результатов

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


Текст = "dsfhs12.432.234.32sdfsdf21.434dsfsd4.34fsdfsdf334.342.34";
МассивЧисел = ИзвлечьМассивЧисел(Текст);

ОбщаяСумма = 0;
Для Каждого ТекЧисло Из МассивЧисел Цикл
    ОбщаяСумма = ОбщаяСумма + ТекЧисло;
    Сообщить("Найдено число: " + Формат(ТекЧисло, "ЧГ=3,0"));
КонецЦикла;

Сообщить("Итоговая сумма: " + ОбщаяСумма);

В результате работы данного алгоритма для нашей строки мы получим следующие значения:

  1. 12432234.32 (точка перед 32 признана дробной).
  2. 21434 (точка перед 434 признана разделителем групп, так как знаков три).
  3. 4.34 (дробное).
  4. 334342.34 (дробное).

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

← На главную