При интеграции 1С с внешними системами, импорте контрагентов, номенклатуры или обработке файлов НСИ (нормативно-справочной информации) разработчики часто сталкиваются с проблемой «грязных» данных. Сегодня в строке разделителем служит точка с запятой (;), завтра — запятая (,), а послезавтра сторонние разработчики присылают выгрузку, где в качестве разделителя используется косая черта или дефис.
В этой статье мы подробно разберем, как эффективно решать задачу парсинга строк с динамическими или множественными разделителями. Мы рассмотрим как встроенные механизмы платформы 1С:Предприятие, так и готовые инструменты из Библиотеки стандартных подсистем (БСП), проанализируем их производительность и разберем неочевидные нюансы работы каждого метода.
Начнем с самого быстрого и простого способа, встроенного непосредственно в платформу 1С, начиная с версии 8.3.6. Многие разработчики привыкли использовать эту функцию только для простых сценариев (например, разделение строки по одному символу), однако у нее есть скрытая и крайне полезная особенность.
Особенность работы: Если в параметр функции СтрРазделить(), отвечающий за разделитель, передать строку из нескольких символов, платформа будет воспринимать каждый символ в этой строке как самостоятельный, независимый разделитель.
Давайте рассмотрим практический пример. Предположим, у нас есть строка контактов, где разделителями могут выступать скобки, дефисы, запятые или точки с запятой. Мы хотим получить массив чистых цифровых сегментов.
// Исходная строка с "хаотичными" разделителями
СтрокаДанных = "8(999)123-45-67;8(888)765,43.21";
// Задаем строку-шаблон, состоящую из всех возможных одиночных разделителей
СтрокаРазделителей = "()-,.;";
// Вызываем платформенную функцию
МассивРезультат = СтрРазделить(СтрокаДанных, СтрокаРазделителей, Ложь);
// Выведем результат для анализа
Для Каждого Элемент Из МассивРезультат Цикл
Сообщить(Элемент);
КонецЦикла;
В результате выполнения данного кода платформа мгновенно разделит строку по любому из встреченных символов указанного набора и вернет массив, содержащий только информативные подстроки. Третий параметр функции — Ложь — указывает системе, что пустые подстроки, образовавшиеся на стыке идущих подряд разделителей (например, скобки и дефиса вместе), нужно автоматически отбрасывать.
Плюсы метода:
Минусы метода:
Что делать, если список разделителей заранее неизвестен, а требования бизнеса постоянно меняются? «Завтра пользователям приснится новый разделитель», — вполне резонное опасение любого разработчика. В Библиотеке стандартных подсистем (БСП) есть изящное решение этой проблемы — функция РазложитьСтрокуВМассивСлов из общего модуля СтроковыеФункцииКлиентСервер.
Эта функция обладает уникальным поведением по умолчанию, которое идеально решает задачу выделения значимых данных из любого текстового хаоса.
Поведение по умолчанию (без передачи разделителей): Если вы вызвать эту функцию, передав ей только анализируемую строку, она автоматически посчитает разделителем любой символ, который не является буквой, цифрой или знаком подчеркивания.
Давайте проанализируем пример совместной работы с этой функцией:
// Строка содержит самые разные спецсимволы, знаки препинания и разделители
ИсходныйТекст = "Товар_1#Категория-А+Склад[Основной]/Ячейка@12";
// Вызываем функцию БСП без указания конкретных разделителей
МассивСлов = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов(ИсходныйТекст);
// Проверяем результат
// Функция вернет массив: ["Товар_1", "Категория", "А", "Склад", "Основной", "Ячейка", "12"]
Для Каждого Слово Из МассивСлов Цикл
Сообщить(Слово);
КонецЦикла;
Этот метод незаменим при разборе поисковых запросов, импорте сложных артикулов или парсинге неструктурированных текстовых файлов, где пользователи могут ставить любые знаки препинания вместо стандартных разделителей.
Если же вам необходимо жестко ограничить список разделителей, функция поддерживает передачу второго параметра. Например, вызов СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов("Код=123,Цена=450", "=,") вернет массив, разделенный строго по указанным символам равенства и запятой.
Иногда перед разработчиком встает противоположная задача: нужно разделить строку по конкретному многосимвольному разделителю, при этом нельзя допустить, чтобы платформа дробила строку по одиночным символам, входящим в этот разделитель.
Для этих целей в БСП предусмотрена функция РазложитьСтрокуВМассивПодстрок из того же общего модуля СтроковыеФункцииКлиентСервер.
Выясним разницу между платформенным методом и методом БСП на наглядном примере. Допустим, у нас есть строка, где данные разделены сочетанием символов "[и]":
СтрокаДанных = "Яблоки[и]Груши[и]Апельсины";
Посмотрим, что произойдет при использовании разных методов:
Массив = СтрРазделить(СтрокаДанных, "[и]");
// Результат будет испорчен! Платформа воспримет символы "[", "и", "]" как три независимых разделителя.
// Мы получим массив: ["Яблоки", "Груш", "Апельс", "ны"]
Массив = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СтрокаДанных, "[и]");
// Результат правильный! Функция воспринимает "[и]" как единую неделимую конструкцию-разделитель.
// Мы получим массив: ["Яблоки", "Груши", "Апельсины"]
Кроме того, у функции РазложитьСтрокуВМассивПодстрок есть крайне полезный четвертый параметр — СокращатьНепечатаемыеСимволы (по умолчанию принимает значение Ложь). Если установить его в значение Истина, функция автоматически удалит все пробелы, знаки табуляции и переносы строк по краям каждой полученной подстроки, избавляя вас от необходимости писать дополнительный цикл с вызовом функции СокрЛП().
Если в вашей конфигурации по какой-то причине отсутствует БСП (например, это старая самописная конфигурация на обычных формах), а режим совместимости не позволяет использовать платформенную функцию СтрРазделить(), можно применить классический «велосипед», проверенный годами.
Суть метода заключается в предварительном приведении всех нестандартных и динамических разделителей к одному «эталонному» символу (например, к запятой или к переносу строки) с последующим делением стандартными средствами.
Рассмотрим, как реализовать этот алгоритм по шагам:
// Исходная строка с неопределенными разделителями
ГрязнаяСтрока = "Значение1;Значение2|Значение3,Значение4";
// Шаг 1: Приводим все потенциальные разделители к одному эталонному (например, к запятой)
ЧистаяСтрока = ГрязнаяСтрока;
ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, ";", ",");
ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, "|", ",");
// Шаг 2: Преобразуем строку в многострочный текст (заменяем запятую на Символы.ПС)
МногострочныйТекст = СтрЗаменить(ЧистаяСтрока, ",", Символы.ПС);
// Шаг 3: Заполняем массив, обходя строки полученного текста
МассивРезультат = Новый Массив;
Для НомерСтроки = 1 По СтрЧислоСтрок(МногострочныйТекст) Цикл
ТекущаяПодстрока = СокрЛП(СтрПолучитьСтроку(МногострочныйТекст, НомерСтроки));
Если НЕ ПустаяСтрока(ТекущаяПодстрока) Тогда
МассивРезультат.Добавить(ТекущаяПодстрока);
EndIf;
КонецЦикла;
Важное предупреждение по производительности: Данный метод рекомендуется использовать только в крайних случаях на устаревших платформах. Конструкции с частым вызовом СтрПолучитьСтроку() внутри больших циклов работают медленно на больших объемах данных, так как платформа каждый раз осуществляет позиционирование в строке с самого начала.
Для того чтобы вам было проще определиться с выбором инструмента в реальной разработке, мы подготовили сравнительную таблицу:
| Критерий сравнения | СтрРазделить() (Платформа) | РазложитьСтрокуВМассивСлов (БСП) | РазложитьСтрокуВМассивПодстрок (БСП) |
|---|---|---|---|
| Минимальная версия платформы | 8.3.6 (без режима совместимости) | Любая (где установлена БСП) | Любая (где установлена БСП) |
| Скорость работы | Максимальная (C++) | Высокая (Встроенный язык) | Высокая (Встроенный язык) |
| Как трактует строку разделителей | Каждый символ — отдельный разделитель | Каждый символ — отдельный разделитель | Вся строка — один целый разделитель |
| Автоматический режим без разделителей | Нет | Да (деление по всем спецсимволам) | Нет |
| Авто-очистка пробелов (Trim) | Нет | Нет | Да (при установке 4-го параметра) |
Мы проанализировали четыре практических способа разделения строк в 1С. Для большинства современных задач оптимальным выбором будет использование быстрой платформенной функции СтрРазделить() с передачей в нее строки всех возможных разделителей. Если же формат входных данных непредсказуем, смело используйте функцию БСП РазложитьСтрокуВМассивСлов() — она убережет ваш код от ошибок при внезапном изменении структуры внешних файлов.