При интеграции 1С с внешними инструментами, такими как ffmpeg или ffprobe, разработчики часто сталкиваются с необходимостью парсинга текстового вывода. Типичная проблема заключается в том, что строка разделена запятыми, но внутри некоторых элементов (токенов) в скобках также могут встречаться запятые. Обычная функция СтрРазделить в данном случае разобьет строку некорректно. Рассмотрим несколько эффективных способов решения этой задачи: от классических алгоритмов до современных возможностей платформы и внешних утилит.
Проанализируем наиболее надежный алгоритмический способ. Если мы не можем использовать регулярные выражения или изменить формат входных данных, нам придется обрабатывать строку символ за символом. Основная идея заключается в использовании переменной-счетчика, которая отслеживает уровень вложенности скобок. Мы будем считать запятую разделителем только в том случае, если мы находимся «снаружи» любых скобок (счетчик равен 0).
Рассмотрим реализацию этого алгоритма на языке 1С:
Функция ИзвлечьТокенСУчетомСкобок(Знач ИсходнаяСтрока, НужныйИндекс) Экспорт
ТекущийИндекс = 1;
Результат = "";
СчетчикВложенности = 0;
Для Позиция = 1 По СтрДлина(ИсходнаяСтрока) Цикл
Символ = Сред(ИсходнаяСтрока, Позиция, 1);
// Отслеживаем вход и выход из скобок
Если Символ = "(" Тогда
СчетчикВложенности = СчетчикВложенности + 1;
ИначеЕсли Символ = ")" Тогда
СчетчикВложенности = СчетчикВложенности - 1;
КонецЕсли;
// Проверяем, является ли символ разделителем
Если Символ = "," И СчетчикВложенности = 0 Тогда
ТекущийИндекс = ТекущийИндекс + 1;
Продолжить;
КонецЕсли;
// Если мы дошли до нужного нам токена, накапливаем символы
Если ТекущийИндекс = НужныйИндекс Тогда
Результат = Результат + Символ;
ИначеЕсли ТекущийИндекс > НужныйИндекс Тогда
// Мы уже прошли нужный токен, можно выходить из цикла
Прервать;
КонецЕсли;
КонецЦикла;
Возврат СокрЛП(Результат);
КонецФункции
Этот метод хорош тем, что он корректно обрабатывает даже вложенные скобки, например: "Параметр, Значение(внутри(еще, глубже), и тут), Конец". Вызов ИзвлечьТокенСУчетомСкобок(Строка, 2) вернет "Значение(внутри(еще, глубже), и тут)".
Если ваша конфигурация работает на платформе версии 8.3.23 и выше, мы можем воспользоваться встроенными функциями для работы с регулярными выражениями. Проанализируем два подхода в рамках этого метода.
Вариант А. Очистка строки от скобок. Если содержимое скобок нам не важно, мы можем просто удалить их вместе со всем содержимым, а затем применить стандартный СтрРазделить.
// Удаляем все, что находится внутри круглых скобок
Шаблон = "\([^)]*\)";
СтрокаБезСкобок = СтрЗаменитьПоРегулярномуВыражению(ИсходнаяСтрока, Шаблон, "");
// Теперь можем смело делить по запятой
МассивТокенов = СтрРазделить(СтрокаБезСкобок, ",");
Если МассивТокенов.Количество() >= 3 Тогда
Результат = СокрЛП(МассивТокенов[2]); // Индексация массива начинается с 0
КонецЕсли;
Вариант Б. Поиск по паттерну. Если нам известно, что третий токен — это разрешение видео (например, 1920x1080), мы можем искать его напрямую, не привязываясь к порядковому номеру запятой. Разберем пример поиска паттерна «число-икс-число».
ШаблонРазрешения = "\d{3,5}x\d{3,5}"; // Ищем числа от 3 до 5 знаков, разделенные 'x'
РезультатыПоиска = РезультатПоискаПоРегулярномуВыражению(ИсходнаяСтрока, ШаблонРазрешения);
Если РезультатыПоиска.Количество() > 0 Тогда
Результат = РезультатыПоиска[0].Значение;
КонецЕсли;
Выясним причину, по которой парсинг стандартного вывода ffmpeg считается «плохим тоном». Текстовый вывод предназначен для чтения человеком, и его формат может незначительно меняться от версии к версии. Гораздо надежнее заставить утилиту отдавать данные в структурированном виде.
Рассмотрим ключи ffprobe, которые избавят нас от необходимости сложного парсинга:
-print_format json. В 1С полученную строку можно мгновенно превратить в Структура или Соответствие с помощью функции ПрочитатьJSON(). Это исключает любые ошибки с запятыми.-print_format flat выведет данные в виде streams.stream.0.width=1920. Такую строку легко разбирать простым поиском подстроки или СтрРазделить по знаку равенства.-show_entries stream=width,height -of csv=s=x:p=0. На выходе вы получите готовую строку вида 1920x1080.
Пример вызова из 1С с использованием формата flat:
Команда = "ffprobe -v quiet -select_streams v:0 -show_entries stream=width,height -of default=noprint_wrappers=1 ""C:\video.mp4""";
// Вывод будет примерно таким:
// width=1920
// height=1080
Если вы предпочитаете работать со стандартными функциями, можно применить комбинированный метод. Разберем ситуацию: мы сначала разбиваем строку «в лоб» через СтрРазделить(Строка, ","), а затем объединяем элементы массива, в которых нарушен баланс скобок.
Проанализируем логику: если в текущем элементе массива открывающих скобок больше, чем закрывающих, значит, следующий элемент массива — это продолжение текущего токена. Мы «склеиваем» их через запятую и продолжаем проверку. Это чуть сложнее в реализации, но работает быстрее, чем посимвольный перебор всей огромной строки.
Важные рекомендации:
СокрЛП() после извлечения токена, так как после запятых в выводе консольных утилит часто идут пробелы.