При интеграции 1С с внешними системами или при обработке текстовых данных часто возникает задача разбора (парсинга) сложных строк. Типичный пример — строка, в которой перемешаны текстовые и числовые данные, например: "Ветчина Мраморная вар. ПГН 400.00 x 0.83 = 332.00". Нам необходимо разложить эту информацию на четыре составляющие: Наименование, Цена, Количество и Сумма.
Сложность заключается в том, что наименование товара может содержать пробелы, цифры и даже символы, которые используются как разделители (например, "х"). В этой статье мы разберем несколько эффективных способов решения этой задачи, начиная от простых манипуляций с массивами и заканчивая использованием регулярных выражений.
Проанализируем структуру нашей строки. Мы видим, что в конце всегда идут числовые показатели, разделенные пробелами и символами «x» и «=». Если мы разделим строку по пробелам в массив, то нужные нам данные (сумма, количество, цена) всегда будут находиться на определенных позициях относительно конца массива. Это самый надежный способ, если формат «Цена x Кол-во = Сумма» строго соблюдается.
Разберем алгоритм по шагам:
Реализуем этот алгоритм на языке 1С:
Функция РазобратьСтрокуЧерезМассив(ВхСтрока)
// Разделяем строку по пробелам
МассивСлов = СтрРазделить(ВхСтрока, " ", Ложь);
МаксИндекс = МассивСлов.ВГраница();
// Проверяем, достаточно ли элементов для разбора
Если МаксИндекс < 5 Тогда
Возврат Неопределено;
КонецЕсли;
// Извлекаем данные с конца массива
Сумма = МассивСлов.Получить(МаксИндекс);
Количество = МассивСлов.Получить(МаксИндекс - 2);
Цена = МассивСлов.Получить(МаксИндекс - 4);
// Удаляем из массива цену, "x", количество, "=" и сумму
// Удаляем 5 раз элемент на позиции (МаксИндекс - 4)
Для К = 1 По 5 Цикл
МассивСлов.Удалить(МаксИндекс - 4);
КонецЦикла;
// Оставшиеся части соединяем в наименование
Наименование = СтрСоединить(МассивСлов, " ");
// Формируем результат
Результат = Новый Структура;
Результат.Вставить("Наименование", Наименование);
Результат.Вставить("Цена", Цена);
Результат.Вставить("Количество", Количество);
Результат.Вставить("Сумма", Сумма);
Возврат Результат;
КонецФункции
Если в наименовании товара встречаются сложные символы или мы хотим добиться максимальной гибкости, стоит рассмотреть использование регулярных выражений. В 1С это реализуется через COM-объект VBScript.RegExp. Регулярное выражение позволяет описать шаблон строки целиком.
Рассмотрим шаблон: (^.+?) (\d+\.\d{2}) x (\d+\.\d{2,3}) = (\d+\.\d{2})$
(^.+?) — захватывает все символы с начала строки до первого совпадения со следующей частью (Наименование).(\d+\.\d{2}) — ищет число с двумя знаками после точки (Цена).x — ищет разделитель (важно учитывать и латинскую "x", и кириллическую "х").(\d+\.\d{2,3}) — ищет число (Количество).= — ищет знак равенства.(\d+\.\d{2})$ — ищет число в самом конце строки (Сумма).Пример реализации с использованием регулярных выражений:
Функция РазобратьСтрокуRegExp(ВхСтрока)
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина;
RegExp.Global = Ложь;
// Шаблон учитывает возможную разную раскладку буквы х
RegExp.Pattern = "(^.+?)\s+(\d+\.\d+)\s+[xх]\s+(\d+\.\d+)\s+=\s+(\d+\.\d+)";
Matches = RegExp.Execute(ВхСтрока);
Если Matches.Count > 0 Тогда
Match = Matches.Item(0);
Результат = Новый Структура;
Результат.Вставить("Наименование", Match.SubMatches.Item(0));
Результат.Вставить("Цена", Match.SubMatches.Item(1));
Результат.Вставить("Количество", Match.SubMatches.Item(2));
Результат.Вставить("Сумма", Match.SubMatches.Item(3));
Возврат Результат;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Проанализируем еще один подход. Начиная с версии 8.3.8, в 1С появилась возможность использовать функцию СтрНайти с параметром НаправлениеПоиска.СКонца. Это работает быстрее, чем создание промежуточных массивов, так как мы просто вычисляем индексы символов-разделителей.
Выясним логику поиска: 1. Находим позицию последнего знака "=". Всё, что правее — Сумма. 2. Находим позицию символа "x" (или "х"), который стоит левее знака "=". Всё, что между ними — Количество. 3. Находим пробел перед символом "x". Всё, что между этим пробелом и "x" — Цена. 4. Всё, что левее цены — Наименование.
При работе с реальными данными мы часто сталкиваемся с «грязными» строками. Разберем основные проблемы и способы их решения:
СтрРазделить с обычным пробелом его не увидит. Перед обработкой всегда делайте замену:
Стр = СтрЗаменить(Стр, Символы.НПП, " ");
Число() в 1С может ожидать запятую в зависимости от региональных настроек сервера или клиента. Рекомендуется принудительно заменять точки на запятые перед преобразованием типа:
ТекЦена = Число(СтрЗаменить(ЦенаИзСтроки, ".", ","));
Цена * Количество = Сумма. Это позволит отсечь строки, где парсер сработал некорректно из-за специфических названий товаров (например, если в названии товара есть конструкция типа "Винт 3x15").Используя предложенные методы, мы можем построить надежную систему импорта данных, которая справится с большинством текстовых строк, встречающихся в практике разработчика 1С.