Как программно обработать и нормализовать текст по шаблону в 1С?

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

В процессе интеграции 1С с внешними системами или при загрузке банковских выписок мы часто сталкиваемся с проблемой «грязных» данных. Пользователи или сторонние программы могут вводить информацию в произвольном формате: использовать разные разделители (точка вместо запятой), менять символы валют (KZT вместо тг), использовать разные префиксы (N вместо №) или вовсе пропускать спецсимволы. Наша задача — привести такие строки к единому каноническому виду, пригодному для дальнейшей обработки в системе.

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

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

Регулярные выражения — это, пожалуй, самый эффективный и лаконичный способ решения подобных задач. Несмотря на кажущуюся сложность, они позволяют одним выражением описать все возможные вариации написания строки. В среде Windows 1С работает с регулярными выражениями через COM-объект VBScript.RegExp.

Проанализируем ситуацию: нам нужно извлечь номер счета и сумму. Номер счета обычно начинается с «№» или «N», а сумма содержит цифры и разделитель (точку или запятую). Разберем по шагам создание такого парсера:


// Создаем объект регулярного выражения
RegExp = Новый COMОбъект("VBScript.RegExp");

// Описываем шаблон:
// (?:N|№) - ищем префикс N или № (без захвата в группу)
// (\d+) - первая группа: захватываем цифры номера счета
// (?:\s*[-= ]\s*) - ищем разделитель (тире, равно или пробел), игнорируя пробелы вокруг
// (\d+[\.,]\d+|\d+) - вторая группа: захватываем сумму (целую часть и дробную через . или ,)
RegExp.Pattern = "(?:N|№)\s*(\d+)\s*[-=\s]\s*(\d+[\.,]\d+|\d+)";
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;

ТекстИсточник = "№742020-996819,02тг №742019=993657.6";
Результаты = RegExp.Execute(ТекстИсточник);

Для Каждого Матч Из Результаты Цикл
    НомерСчета = Матч.SubMatches(0);
    СуммаСтрокой = Матч.SubMatches(1);
    
    // Приводим сумму к числовому формату 1С
    СуммаСтрокой = СтрЗаменить(СуммаСтрокой, ".", ",");
    Сумма = Число(СуммаСтрокой);
    
    Сообщить("Найдено: Счет №" + НомерСчета + ", Сумма: " + Сумма);
КонецЦикла;

Преимущества этого подхода: гибкость. Мы можем легко добавить новые варианты разделителей в шаблон, не переписывая программный код. Рассмотрим подробнее, как это работает: метод Execute находит все вхождения шаблона в строке, а коллекция SubMatches позволяет вытащить именно те части, которые были заключены в круглые скобки в регулярном выражении.

Метод 2: Последовательная нормализация (Очистка)

Если по каким-то причинам использование регулярных выражений нежелательно, мы можем применить стратегию последовательной замены «мусорных» символов на стандартные. Выясним причину, по которой этот метод часто выбирают новички: он более нагляден при отладке.

Алгоритм действий будет следующим:

  1. Приведем строку к верхнему регистру для упрощения поиска.
  2. Заменим все известные варианты валют (KZT, тг, тенге) на пустую строку или единый маркер.
  3. Заменим все возможные разделители между номером и суммой (тире, равно) на пробел.
  4. Разобьем строку в массив, используя пробел как разделитель.

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


Функция НормализоватьСтроку(Знач ВходнаяСтрока)
    // Убираем валюту
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "KZT", "");
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "тг", "");
    
    // Унифицируем разделитель номера и суммы
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "-", " ");
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "=", " ");
    
    // Убираем спецсимволы номера
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "№", "");
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "N", "");
    
    // Теперь строка выглядит примерно так: "742020 996819,02 742019 993657.6"
    Возврат СократитьЛП(ВходнаяСтрока);
КонецФункции

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

Метод 3: Конечный автомат (Посимвольный перебор)

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

Проанализируем ситуацию: наше состояние может быть либо «Ожидаем номер», либо «Читаем номер», либо «Читаем сумму». Посмотрим на пример реализации:


Текст = "№742020-996819,02тг";
ТекущийНомер = "";
ТекущаяСумма = "";
Состояние = "ПОИСК_НОМЕРА"; 

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

Важный момент: при парсинге сумм всегда учитывайте, что в качестве разделителя может выступать как точка, так и запятая. Перед преобразованием строки в тип Число обязательно приводите разделитель к тому виду, который установлен в системных настройках вашей ОС (в России это обычно запятая).

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

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), вам доступны мощные инструменты в общем модуле СтроковыеФункцииКлиентСервер. Рассмотрим подробнее функцию РазложитьСтрокуВМассивПодстрок. Она примечательна тем, что в качестве разделителя может принимать не одну строку, а целый массив возможных разделителей.

Это позволяет нам в одну строку кода разделить «грязную» строку по всем возможным проблемным символам:


Разделители = Новый Массив;
Разделители.Добавить("=");
Разделители.Добавить("-");
Разделители.Добавить(" ");
Разделители.Добавить("№");
Разделители.Добавить("N");

ЧастиСтроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ТекстИсточник, Разделители, Истина);

Параметр Истина в конце функции означает, что пустые подстроки будут автоматически удалены из результата. После этого нам останется только обойти массив и идентифицировать, где номер, а где сумма (например, по наличию разделителя дробной части или длине строки).

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

← На главную