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

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

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

Преобразование текста в массив строк

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


// Входящий текст может содержать переносы строк (Символы.ПС)
МассивСтрок = СтрРазделить(ВходящийТекст, Символы.ПС, Ложь);

Для К = 0 По МассивСтрок.ВГраница() Цикл
    ТекущаяСтрока = МассивСтрок[К];
    
    // Ищем строку, содержащую метку "цена на"
    Если СтрНайти(ТекущаяСтрока, "цена на") > 0 Тогда
        // Мы нашли нужную строку, теперь можем извлечь дату и цену
        // ... (логика извлечения)
        
        // Чтобы получить данные из СЛЕДУЮЩЕЙ строки, обращаемся к индексу К + 1
        Если К + 1 <= МассивСтрок.ВГраница() Тогда
            СледующаяСтрока = МассивСтрок[К + 1];
            Сообщить("Наименование товара найдено: " + СледующаяСтрока);
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

В данном примере мы используем цикл Для, который позволяет нам управлять индексом К. Важно всегда проверять условие К + 1 <= МассивСтрок.ВГраница(), чтобы избежать ошибки выхода за границы массива, если ключевое слово окажется в самой последней строке документа.

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

Часто данные внутри строки разделены переменным количеством пробелов. Рассмотрим ситуацию, когда нам нужно извлечь цену и дату. Функция СтрРазделить поможет нам разбить строку на отдельные слова. Проанализируем пример, в котором стоимость находится после определенного количества слов.


// Допустим, ТекущаяСтрока = "цена на 01.08.2022 г. 157 руб."
ДанныеСтроки = СтрРазделить(ТекущаяСтрока, " ", Ложь);

// Извлекаем дату (она идет под индексом 2, если считать с 0: "цена"(0), "на"(1), "01.08.2022"(2))
ДатаПрайса = ДанныеСтроки[2];

// Извлекаем цену (она идет под индексом 4: "г."(3), "157"(4))
ЦенаЗначение = ДанныеСтроки[4];

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

Нормализация пробелов в строке

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


// Способ через СтрРазделить и СтрСоединить
// Этот метод эффективно удаляет все лишние пустые элементы
Текст = "цена    на   01.08.2022  г.    157  руб.";
МассивСлов = СтрРазделить(Текст, " ", Ложь); // Ложь означает, что пустые строки не включаются
НормализованныйТекст = СтрСоединить(МассивСлов, " ");
// Результат: "цена на 01.08.2022 г. 157 руб."

Разберем, как это работает: функция СтрРазделить с параметром ВключатьПустые = Ложь игнорирует идущие подряд пробелы. Затем СтрСоединить склеивает полученные слова, вставляя между ними ровно по одному пробелу. Это гораздо быстрее и короче, чем использование циклов с функцией СтрЗаменить.

Обработка спецсимволов и неразрывных пробелов

Проанализируем ситуацию, когда визуально пробелы есть, но код их "не видит". В текстах, пришедших из веб-форм или PDF, часто встречается неразрывный пробел (символ с кодом 160). Обычная функция СтрЗаменить(Текст, " ", "") его не удалит. Посмотрим, как очистить текст от таких сюрпризов:


// Заменяем неразрывный пробел на обычный
Текст = СтрЗаменить(Текст, Символ(160), " ");
// Удаляем символы табуляции
Текст = СтрЗаменить(Текст, Символы.Таб, " ");
// Теперь можно выполнять нормализацию пробелов, описанную выше

Продвинутый метод: Регулярные выражения (RegExp)

Для наиболее сложных случаев, когда структура строки может меняться (например, дата может быть в начале или в конце), рекомендуется использовать регулярные выражения. Это мощный инструмент, доступный в 1С через COM-объект VBScript.RegExp. Рассмотрим пример поиска цены и даты независимо от количества пробелов.


RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина;
RegExp.Global = Истина;

// Шаблон для поиска даты в формате ДД.ММ.ГГГГ
RegExp.Pattern = "(\d{2}\.\d{2}\.\d{4})";
Matches = RegExp.Execute(ТекущаяСтрока);

Если Matches.Count > 0 Тогда
    ДатаИзТекста = Matches.Item(0).Value;
КонецЕсли;

// Шаблон для поиска числа перед словом "руб"
RegExp.Pattern = "(\d+)\s+руб";
Matches = RegExp.Execute(ТекущаяСтрока);

Если Matches.Count > 0 Тогда
    ЦенаИзТекста = Matches.Item(0).SubMatches.Item(0);
КонецЕсли;

Использование регулярных выражений позволяет значительно сократить объем кода и сделать алгоритм устойчивым к изменениям формата входящих данных.

Алгоритм "Машина состояний" для многострочного поиска

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

  1. Создаем переменную-флаг ЖдемНаименование = Ложь.
  2. В цикле читаем строки одну за другой.
  3. Если в строке найдено "цена на", извлекаем данные и устанавливаем ЖдемНаименование = Истина.
  4. На следующей итерации цикла, если ЖдемНаименование равно Истина, текущую строку считаем наименованием, сохраняем её и сбрасываем флаг.

ЖдемНаименование = Ложь;
Для Каждого ТекущаяСтрока Из МассивСтрок Цикл
    Если ЖдемНаименование Тогда
        ТоварНаименование = СокрЛП(ТекущаяСтрока);
        // Сохраняем результат в таблицу или базу
        ЖдемНаименование = Ложь;
    ИначеЕсли СтрНайти(ТекущаяСтрока, "цена на") > 0 Тогда
        // Обработка строки с ценой
        ЖдемНаименование = Истина;
    КонецЕсли;
КонецЦикла;

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

Рекомендации по работе с PDF

Поскольку исходным форматом является PDF, важно помнить, что прямое копирование текста или автоматическая конвертация в Excel часто "склеивают" колонки. Если вы программируете на стороне сервера, рассмотрите возможность использования внешних утилит, таких как pdftotext. Вызов такой утилиты через ЗапуститьПриложение позволит получить текстовый файл с сохранением физического расположения слов (layout), что на порядок упростит последующий парсинг в 1С.

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

← На главную