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

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

При автоматической обработке входящих электронных писем, банковских уведомлений или SMS-сообщений часто возникает задача извлечь числовые показатели (например, сумму оплаты) из неструктурированного текста и записать их в реквизиты создаваемого документа. Неправильный разбор строки приводит к ошибкам приведения типов или некорректно заполненным данным.

Разберем типичные ошибки, возникающие при парсинге строк, выясним причины исключения «Преобразование к типу Число не может быть выполнено» и рассмотрим надежные варианты решения этой задачи на платформе 1С:Предприятие.

Почему жесткая привязка к позициям символов не работает

Проанализируем исходный пример текста входящего уведомления:

Vhodyaschiy platezh. Summa 2,222.22 RUB. Otpravitel ******** *******. 16.11.2017.

Попытка извлечь подстроку с помощью функций Сред() или Лев() с жестко фиксированными номерами символов (например, Сред(Текст, 27, 5)) является распространенной ошибкой. Выясним, почему такой подход приводит к сбоям:

  1. Переменная длина суммы: Суммы 10.00, 2,222.22 и 1,500,000.00 имеют разное количество символов. Фиксированное смещение будет либо обрезать значимые цифры, либо захватывать посторонний текст (например, буквы валюты).
  2. Смещение текста: Любое изменение в тексте сообщения перед суммой (другое имя отправителя, дополнительные пробелы или смена шаблона) полностью ломает логику фиксированных позиций.

Причины ошибки «Преобразование к типу Число не может быть выполнено»

Даже если подстрока с суммой выделена, функция Число() может вызвать аварийное завершение программы. Рассмотрим основные причины:

  1. Разделители групп разрядов: В банковских выписках и письмах тысячи часто разделяются запятыми (2,222.22) или пробелами (включая неразрывный пробел Символы.НПП с кодом 160). Функция Число() не может обработать строку с такими символами.
  2. Несоответствие региональных настроек: В русскоязычной локали 1С стандартным десятичным разделителем является запятая, а в строке письма часто используется точка. Если передать строку "2222.22" в Число() при русской локализации сеанса, возникнет ошибка.
  3. Посторонние невидимые символы: В тексте электронных писем часто присутствуют табуляции, переносы строк и спецсимволы разметки HTML, которые не всегда удаляются стандартной функцией СокрЛП().

Способ 1. Динамический поиск границ подстроки по ключевым маркерам

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

Разберем реализацию по шагам:

  1. Находим позицию слова-маркера "Summa " с помощью функции СтрНайти().
  2. Находим позицию маркера валюты " RUB", начиная поиск от маркера начала.
  3. Вырезаем подстроку с помощью функции Сред().
  4. Удаляем запятые (разделители тысяч), пробелы и неразрывные пробелы.
  5. Заменяем точку на запятую (если используется стандартная функция Число()) либо используем универсальные методы преобразования.

Посмотрим на пример кода:


// Исходный текст сообщения
ИсходныйТекст = СтрТЗ.Тело;

МаркерНачала = "Summa ";
МаркерКонца  = " RUB";

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

Способ 2. Использование универсальных методов преобразования типов

Чтобы избежать зависимости от региональных настроек сеанса (где разделителем может быть как точка, так и запятая), рассмотрим альтернативные методы преобразования строки в число.

1. Преобразование через XMLЗначение

Функция XMLЗначение() принимает числа в формате стандарта XML, где разделителем дробной части всегда выступает точка. Если в строке удалены разделители тысяч и оставлена точка, этот метод преобразует строку независимо от языка системы:


// Строка должна содержать только цифры и десятичную точку, например: "2222.22"
СтрЧислаXML = "2222.22";
ЧисловоеЗначение = XMLЗначение(Тип("Число"), СтрЧислаXML);

2. Безопасное приведение через ОписаниеТипов

Метод ПривестиЗначение() объекта ОписаниеТипов удобен тем, что он не вызывает исключений при некорректном формате данных, а возвращает значение по умолчанию (для числа — 0):


ОписаниеЧисла = Новый ОписаниеТипов("Число");
ЧисловоеЗначение = ОписаниеЧисла.ПривестиЗначение(СтрСумма);

Способ 3. Извлечение суммы с помощью регулярных выражений

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

Посмотрим на пример с использованием встроенных объектов платформы:


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

Если РезультатПоиска <> Неопределено И РезультатПоиска.Количество() > 0 Тогда
    НайденнаяГруппа = РезультатПоиска[0];
    
    // Получаем значение первой группы захвата
    СтрСумма = НайденнаяГруппа.Подгруппы[0].Значение;
    
    // Удаляем разделители тысяч
    СтрСумма = СтрЗаменить(СтрСумма, ",", "");
    
    // Преобразуем число в формате XML (с точкой)
    дО.Сумма = XMLЗначение(Тип("Число"), СтрСумма);
КонецЕсли;

Для более ранних версий платформы под управлением операционной системы Windows для аналогичной цели можно использовать COM-объект VBScript.RegExp.

Особенности записи данных в документ

Разберем контекст выполнения кода при загрузке данных:

  1. Загрузка в фоновом режиме: Если разбор писем выполняется регламентным заданием, не следует обращаться к форме документа. Работа ведется непосредственно с объектом: создаем документ через Документы.Оплата.СоздатьДокумент(), заполняем реквизит Сумма числовым значением и вызываем метод Записать(РежимЗаписиДокумента.Запись).
  2. Заполнение в открытой форме: Если код выполняется в модуле управляемой формы, присвоение реквизиту выполняется через основной реквизит формы: Объект.Сумма = ЧисловоеЗначение;, что сразу отобразит результат в пользовательском интерфейсе.
← На главную