В процессе разработки и автоматизации на платформе 1С мы регулярно сталкиваемся с необходимостью обработки строковых данных. Часто информация хранится в виде одной строки, где несколько значений разделены специальным символом или последовательностью символов. Один из самых распространенных сценариев – это разделение строки на две части: до и после определенного разделителя. Например, если у нас есть строка вида "текст/текст1", и нам требуется получить "текст" и "текст1" как отдельные значения для дальнейшей работы. Давайте подробно разберем, как мы можем решить эту задачу, используя различные инструменты и подходы, доступные в 1С.
Этот подход является одним из самых фундаментальных и универсальных, поскольку он основан на базовых строковых функциях, доступных во всех версиях платформы 1С. Он требует несколько шагов, но дает полный контроль над процессом разделения.
Шаг 1: Находим позицию разделителя.
Для начала нам необходимо определить, где именно находится наш символ-разделитель в исходной строке. Для этого мы используем функцию СтрНайти(). Она возвращает числовую позицию первого вхождения указанной подстроки (разделителя), начиная отсчет с 1. Если разделитель не найден, функция вернет 0. Этот шаг критически важен, так как от него зависит корректность дальнейших операций.
ИсходнаяСтрока = "текст/текст1";
Разделитель = "/";
ПозицияРазделителя = СтрНайти(ИсходнаяСтрока, Разделитель);
// Если ПозицияРазделителя = 0, это означает, что разделитель не найден в строке.
Шаг 2: Извлекаем часть строки до разделителя.
После того как мы нашли позицию разделителя, мы можем легко извлечь левую часть строки, то есть все символы, которые находятся до него. Для этого мы используем функцию Лев(). Мы указываем исходную строку и количество символов, которые нужно извлечь. В нашем случае это будет ПозицияРазделителя - 1, чтобы не захватить сам разделитель.
Если ПозицияРазделителя > 0 Тогда
ЧастьДоРазделителя = Лев(ИсходнаяСтрока, ПозицияРазделителя - 1);
// Для строки "текст/текст1" ЧастьДоРазделителя будет равна "текст".
Иначе
ЧастьДоРазделителя = ИсходнаяСтрока;
// Если разделитель не найден, вся строка считается "частью до разделителя".
КонецЕсли;
Шаг 3: Извлекаем часть строки после разделителя.
Чтобы получить правую часть строки, то есть все символы после разделителя, мы используем функцию Сред(). Эта функция позволяет извлечь подстроку, начиная с указанной позиции и до конца строки (если не указана длина). Мы начинаем извлечение с позиции, которая следует сразу за разделителем. Для этого к ПозицияРазделителя мы прибавляем длину самого разделителя (СтрДлина(Разделитель)).
Если ПозицияРазделителя > 0 Тогда
ЧастьПослеРазделителя = Сред(ИсходнаяСтрока, ПозицияРазделителя + СтрДлина(Разделитель));
// Для строки "текст/текст1" ЧастьПослеРазделителя будет равна "текст1".
Иначе
ЧастьПослеРазделителя = "";
// Если разделитель не найден, "часть после разделителя" будет пустой строкой.
КонецЕсли;
Полный пример кода для ручного разделения:
Давайте объединим все эти шаги в единый, более полный пример, который будет учитывать различные сценарии, включая отсутствие разделителя.
ИсходнаяСтрока = "текст/текст1";
Разделитель = "/";
ПозицияРазделителя = СтрНайти(ИсходнаяСтрока, Разделитель);
Если ПозицияРазделителя > 0 Тогда
// Часть строки до разделителя
ЧастьДо = Лев(ИсходнаяСтрока, ПозицияРазделителя - 1);
// Часть строки после разделителя
// Учитываем длину разделителя, чтобы начать извлечение сразу после него
ЧастьПосле = Сред(ИсходнаяСтрока, ПозицияРазделителя + СтрДлина(Разделитель));
Сообщить("Исходная строка: " + ИсходнаяСтрока);
Сообщить("Разделитель: '" + Разделитель + "'");
Сообщить("Часть до разделителя: " + ЧастьДо); // Выведет "текст"
Сообщить("Часть после разделителя: " + ЧастьПосле); // Выведет "текст1"
Иначе
Сообщить("Разделитель '" + Разделитель + "' не найден в строке: " + ИсходнаяСтрока);
Сообщить("Вся строка рассматривается как 'часть до разделителя': " + ИсходнаяСтрока);
Сообщить("Часть 'после разделителя' пуста.");
КонецЕсли;
// Пример с другим разделителем
ИсходнаяСтрока2 = "НомерЗаказа-12345";
Разделитель2 = "-";
ПозицияРазделителя2 = СтрНайти(ИсходнаяСтрока2, Разделитель2);
Если ПозицияРазделителя2 > 0 Тогда
ЧастьДо2 = Лев(ИсходнаяСтрока2, ПозицияРазделителя2 - 1);
ЧастьПосле2 = Сред(ИсходнаяСтрока2, ПозицияРазделителя2 + СтрДлина(Разделитель2));
Сообщить("---");
Сообщить("Исходная строка: " + ИсходнаяСтрока2);
Сообщить("Разделитель: '" + Разделитель2 + "'");
Сообщить("Часть до разделителя: " + ЧастьДо2); // Выведет "НомерЗаказа"
Сообщить("Часть после разделителя: " + ЧастьПосле2); // Выведет "12345"
КонецЕсли;
Этот метод, хотя и требует больше строк кода, предоставляет нам полную гибкость и работает независимо от версии платформы. Однако, для более современных задач и версий 1С существуют более лаконичные и производительные решения.
Начиная с версии платформы 8.3.6, в 1С появилась встроенная функция СтрРазделить(), которая значительно упрощает задачу разделения строки на массив подстрок по заданным разделителям. Это наиболее предпочтительный и производительный способ для большинства случаев, особенно когда разделитель представляет собой один символ или набор независимых символов.
Синтаксис и параметры функции СтрРазделить().
Функция имеет следующий синтаксис, который мы найдем в документации глобального контекста:
СтрРазделить(<Строка>, <Разделитель>, <ВключатьПустые>)
<Строка> (обязательный):
Это исходная строка, которую мы хотим разделить на части.
<Разделитель> (обязательный):
Здесь кроется ключевое отличие: этот параметр представляет собой строку символов, где каждый отдельный символ из этой строки является потенциальным разделителем. Например, если мы передадим "/- " (косая черта, дефис, пробел), то исходная строка будет разделена по любому вхождению `/`, `-` или ` `. Это важно понимать, так как СтрРазделить() не рассматривает многосимвольные последовательности (например, ", " как один разделитель, а будет разделять по "," и по " " отдельно).
<ВключатьПустые> (необязательный):
Этот параметр имеет тип Булево и указывает, следует ли включать пустые строки в результирующий массив. Пустые строки могут образоваться, если разделители идут подряд (например, "данные//данные"), или если разделитель находится в начале/конце строки. По умолчанию значение Истина, то есть пустые строки будут включены. Если установить Ложь, пустые подстроки будут игнорироваться.
Возвращаемое значение функции — это Массив строк, которые получились в результате разделения исходной строки.
Пример использования СтрРазделить():
В нашем исходном случае, когда разделителем является одиночный символ `/`, функция СтрРазделить() подходит идеально и значительно упрощает код по сравнению с ручным методом.
ИсходнаяСтрока = "текст/текст1";
Разделитель = "/";
// Разделяем строку. Третий параметр (ВключатьПустые) по умолчанию Истина.
МассивПодстрок = СтрРазделить(ИсходнаяСтрока, Разделитель);
// Проверяем наличие элементов в массиве и выводим их
Если МассивПодстрок.ВГраница() >= 0 Тогда
Сообщить("Часть до разделителя: " + МассивПодстрок[0]); // Выведет "текст"
КонецЕсли;
Если МассивПодстрок.ВГраница() >= 1 Тогда
Сообщить("Часть после разделителя: " + МассивПодстрок[1]); // Выведет "текст1"
Иначе
Сообщить("После разделителя ничего нет или разделителя нет в исходной строке.");
КонецЕсли;
Сообщить("---");
// Пример с несколькими разделителями из набора и пустыми строками
ИсходнаяСтрока2 = "данные1//данные3; данные4";
Разделитель2 = "/;"; // Разделители: косая черта и точка с запятой
МассивПодстрок2 = СтрРазделить(ИсходнаяСтрока2, Разделитель2);
// МассивПодстрок2 будет: {"данные1", "", "данные3", " данные4"}
// Обратите внимание на пробел перед "данные4", так как пробел не был указан как разделитель.
Для Каждого ЭлементМассива Из МассивПодстрок2 Цикл
Сообщить("Элемент: '" + ЭлементМассива + "'");
КонецЦикла;
Сообщить("---");
// Пример с явным указанием не включать пустые строки
ИсходнаяСтрока3 = "данные1::данные3";
Разделитель3 = ":";
МассивПодстрок3 = СтрРазделить(ИсходнаяСтрока3, Разделитель3, Ложь);
// МассивПодстрок3 будет: {"данные1", "данные3"}
Для Каждого ЭлементМассива Из МассивПодстрок3 Цикл
Сообщить("Элемент без пустых: '" + ЭлементМассива + "'");
КонецЦикла;
Порядок элементов в результирующем массиве.
Один из вопросов, который часто возникает у разработчиков, касается порядка элементов в массиве после разделения. Мы можем быть уверены: СтрРазделить() всегда помещает части строки в результирующий массив слева направо, в том порядке, в котором они встречаются в исходной строке. Таким образом, элемент МассивПодстрок[0] всегда будет соответствовать первой части строки (до первого разделителя), МассивПодстрок[1] — второй части (между первым и вторым разделителями) и так далее. Это поведение предсказуемо и стабильно, что упрощает дальнейшую обработку данных.
Функция СтрРазделить() является платформенной, что обеспечивает ее высокую производительность и надежность. Мы настоятельно рекомендуем использовать ее везде, где это возможно, особенно если разделитель является одиночным символом или набором символов, так как это самый эффективный способ решения задачи.
Для случаев, когда разделитель представляет собой последовательность из нескольких символов (например, "<br>", "||", ", "), или если мы работаем с более старыми версиями платформы, где СтрРазделить() еще не была доступна (до 8.3.6), часто используется функция РазложитьСтрокуВМассивПодстрок(). Эта функция, как правило, находится в общих модулях типовых конфигураций, входящих в состав Библиотеки Стандартных Подсистем (БСП), например, в модуле СтроковыеФункцииКлиентСервер или ОбщегоНазначения в более старых редакциях.
Особенности и параметры функции РазложитьСтрокуВМассивПодстрок().
Главное отличие этой функции от СтрРазделить() заключается в том, что она воспринимает второй параметр — Разделитель — как цельную подстроку-разделитель, а не как набор отдельных символов. Это ее ключевое преимущество для определенных сценариев. Рассмотрим упрощенный вариант ее реализации, который демонстрирует логику работы и часто встречается в БСП:
// Пример кода функции из БСП (может незначительно отличаться в разных версиях БСП)
Функция РазложитьСтрокуВМассивПодстрок(Знач Значение, Знач Разделитель = ",", Знач ПропускатьПустыеСтроки = Неопределено,
СокращатьНепечатаемыеСимволы = Ложь) Экспорт
// Оптимизация: если разделитель - один символ и определенные условия, используем платформенную СтрРазделить
Если СтрДлина(Разделитель) = 1
И ПропускатьПустыеСтроки = Неопределено
И СокращатьНепечатаемыеСимволы Тогда
Результат = СтрРазделить(Значение, Разделитель, Ложь); // Использование платформенной функции
Для Индекс = 0 По Результат.ВГраница() Цикл
Результат[Индекс] = СокрЛП(Результат[Индекс])
КонецЦикла;
Возврат Результат;
КонецЕсли;
Результат = Новый Массив;
// Логика для обеспечения обратной совместимости и обработки специфических случаев
Если ПропускатьПустыеСтроки = Неопределено Тогда
ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь);
Если ПустаяСтрока(Значение) Тогда
Если Разделитель = " " Тогда
Результат.Добавить("");
КонецЕсли;
Возврат Результат;
КонецЕсли;
КонецЕсли;
// Основной цикл разделения строки с помощью СтрНайти и Сред
Позиция = СтрНайти(Значение, Разделитель);
Пока Позиция > 0 Цикл
Подстрока = Лев(Значение, Позиция - 1);
Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
Если СокращатьНепечатаемыеСимволы Тогда
Результат.Добавить(СокрЛП(Подстрока));
Иначе
Результат.Добавить(Подстрока);
КонецЕсли;
КонецЕсли;
Значение = Сред(Значение, Позиция + СтрДлина(Разделитель));
Позиция = СтрНайти(Значение, Разделитель);
КонецЦикла;
// Добавляем оставшуюся часть строки после последнего разделителя
Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Значение) Тогда
Если СокращатьНепечатаемыеСимволы Тогда
Результат.Добавить(СокрЛП(Значение));
Иначе
Результат.Добавить(Значение);
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Основные параметры этой функции:
Значение:
Исходная строка, которую необходимо разделить.
Разделитель:
Подстрока-разделитель. Это может быть как одиночный символ (например, "/"), так и последовательность символов (например, ", ", "||", "<br>"). Функция ищет и разделяет строку именно по этой подстроке целиком.
ПропускатьПустыеСтроки:
Булево значение. Если установлено в Истина, пустые элементы, которые могут образоваться при разделении (например, если разделители идут подряд), не будут добавлены в результирующий массив.
СокращатьНепечатаемыеСимволы:
Булево значение. Если установлено в Истина, к каждой извлеченной подстроке будет автоматически применена функция СокрЛП(), которая удаляет пробелы и непечатаемые символы с начала и конца строки.
Важно отметить, что современные реализации этой функции в БСП часто включают оптимизацию: если разделитель является одним символом и выполняются определенные условия (например, не требуется сокращение непечатаемых символов), функция может внутри себя вызывать платформенную СтрРазделить() для повышения производительности, как показано в начале приведенного кода.
Пример использования РазложитьСтрокуВМассивПодстрок():
Для нашего случая "текст/текст1" с одиночным разделителем `/` функция также сработает.
// Предполагаем, что функция СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок доступна.
// Обычно она находится в общем модуле "СтроковыеФункцииКлиентСервер".
ИсходнаяСтрока = "текст/текст1";
Разделитель = "/";
МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИсходнаяСтрока, Разделитель);
Если МассивПодстрок.ВГраница() >= 0 Тогда
Сообщить("Часть до разделителя: " + МассивПодстрок[0]); // Выведет "текст"
КонецЕсли;
Если МассивПодстрок.ВГраница() >= 1 Тогда
Сообщить("Часть после разделителя: " + МассивПодстрок[1]); // Выведет "текст1"
Иначе
Сообщить("После разделителя ничего нет или разделителя нет.");
КонецЕсли;
Сообщить("---");
// Пример с составным разделителем, где СтрРазделить() работала бы иначе
ИсходнаяСтрока2 = "Яблоко, Груша, Апельсин";
Разделитель2 = ", "; // Разделитель - строка из двух символов: запятая и пробел
МассивПодстрок2 = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИсходнаяСтрока2, Разделитель2);
// МассивПодстрок2 будет: {"Яблоко", "Груша", "Апельсин"}
// Если бы мы использовали СтрРазделить(ИсходнаяСтрока2, ", "), то результат был бы {"Яблоко", "", "Груша", "", "Апельсин"},
// так как "," и " " были бы разными разделителями, и между ними образовывалась бы пустая строка.
Для Каждого ЭлементМассива Из МассивПодстрок2 Цикл
Сообщить("Элемент с составным разделителем: '" + ЭлементМассива + "'");
КонецЦикла;
Сообщить("---");
// Пример с пропуском пустых строк и сокращением символов
ИсходнаяСтрока3 = " Название1 || Название2 ";
Разделитель3 = "||";
МассивПодстрок3 = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИсходнаяСтрока3, Разделитель3, Истина, Истина);
// МассивПодстрок3 будет: {"Название1", "Название2"}
Для Каждого ЭлементМассива Из МассивПодстрок3 Цикл
Сообщить("Элемент с сокращением и пропуском пустых: '" + ЭлементМассива + "'");
КонецЦикла;
Таким образом, мы видим, что функция из БСП предоставляет нам больше контроля над обработкой разделителя как цельной подстроки и дополнительными опциями, такими как сокращение непечатаемых символов и управление пустыми строками, что делает ее очень гибкой для специфических задач.
Мы рассмотрели три основных подхода к разделению строк в 1С. Каждый из них имеет свои преимущества и оптимальные сценарии использования. Давайте кратко подытожим, чтобы вы могли выбрать наиболее подходящий метод для вашей задачи.
Ручной метод (СтрНайти, Лев, Сред):
Плюсы:
Максимальная совместимость со всеми версиями платформы 1С. Полный контроль над логикой процесса разделения, что полезно для очень специфических или нетипичных сценариев.
Минусы:
Код получается более громоздким и многословным. Требует выполнения нескольких операций и ручной обработки исключений (например, что делать, если разделитель отсутствует в строке).
Когда использовать:
В старых конфигурациях, где нет доступа к современным функциям платформы (как СтрРазделить()) или функциям БСП. Также подходит, если требуется очень специфическая логика разделения, которая не укладывается в стандартные функции.
Платформенная функция СтрРазделить():
Плюсы:
Высокая производительность, поскольку это встроенная функция платформы. Код лаконичен и прост для чтения. Порядок элементов в результирующем массиве предсказуем (слева направо).
Минусы:
Разделитель воспринимается как набор отдельных символов, а не как цельная подстрока. Доступна только начиная с версии платформы 8.3.6.
Когда использовать:
В большинстве современных задач, когда разделитель представляет собой один символ (например, "/", " ", ";") или набор независимых символов (например, ",; "). Это предпочтительный метод для таких случаев благодаря своей эффективности и простоте.
Функция из БСП РазложитьСтрокуВМассивПодстрок():
Плюсы:
Позволяет использовать многосимвольный разделитель как единое целое (например, "<br>", "||", ", "). Предоставляет дополнительные опции, такие как пропуск пустых строк и автоматическое сокращение пробелов (СокрЛП()) для каждой части.
Минусы:
Может быть менее производительной, чем платформенная СтрРазделить(), если только не задействованы внутренние оптимизации БСП, использующие СтрРазделить(). Требует наличия Библиотеки Стандартных Подсистем в конфигурации.
Когда использовать:
Когда разделитель является сложной, многосимвольной подстрокой, а не одиночным символом. Также подходит, если требуется дополнительная обработка каждой части (например, СокрЛП()) или в конфигурациях до 8.3.6, если доступна соответствующая функция БСП.
Ваш выбор метода должен основываться на конкретных требованиях к типу разделителя (одиночный символ, набор символов или многосимвольная подстрока), версии используемой платформы 1С и доступности библиотечных функций в вашей конфигурации.
Для максимально сложных и гибких задач разбора строк, выходящих за рамки простого разделения до и после символа, начиная с платформы 8.3.23, в 1С появилась встроенная поддержка регулярных выражений. Это невероятно мощный инструмент, который позволяет разделять и находить подстроки по сложным шаблонам, а не только по фиксированным разделителям. Если вам нужно разделить строку по одному или нескольким пробельным символам подряд, извлечь все телефонные номера или адреса электронной почты, соответствующие определенному формату, или проверить строку на соответствие сложному шаблону (например, формату номера документа), регулярные выражения — ваш выбор.
Для работы с регулярными выражениями в платформу были добавлены следующие новые функции:
СтрНайтиПоРегулярномуВыражению()СтрЗаменитьПоРегулярномуВыражению()СтрПодобнаПоРегулярномуВыражению()Хотя использование регулярных выражений выходит за рамки нашей текущей задачи по разделению строки до и после одного символа, мы настоятельно рекомендуем изучить их возможности для более продвинутых сценариев работы со строками, так как они открывают двери к решению очень сложных задач по парсингу и валидации строковых данных.
При разделении строк важно внимательно отнестись к тому, как обрабатываются пустые подстроки. Они могут появиться в нескольких сценариях:
"данные1;;данные3", между двумя точками с запятой образуется пустая подстрока."/данные1", то перед первым разделителем также образуется пустая подстрока."данные1/", то после последнего разделителя будет пустая подстрока.Функции 1С предоставляют механизмы для управления этим поведением, что позволяет нам получить именно тот результат, который ожидается, и избежать лишних проверок в дальнейшем коде.
У функции СтрРазделить() за это отвечает третий параметр <ВключатьПустые>.
По умолчанию он установлен в Истина, что означает, что все пустые строки, образовавшиеся в результате разделения, будут включены в результирующий массив. Если же мы хотим игнорировать пустые подстроки, следует установить этот параметр в Ложь.
СтрокаСПустыми = "часть1//часть2";
Разделитель = "/";
// Включаем пустые подстроки (по умолчанию Истина)
МассивВключаяПустые = СтрРазделить(СтрокаСПустыми, Разделитель, Истина);
// Результат: {"часть1", "", "часть2"}
Сообщить("Массив включая пустые: " + СтрСоединить(МассивВключаяПустые, "|"));
// Исключаем пустые подстроки
МассивБезПустых = СтрРазделить(СтрокаСПустыми, Разделитель, Ложь);
// Результат: {"часть1", "часть2"}
Сообщить("Массив без пустых: " + СтрСоединить(МассивБезПустых, "|"));
СтрокаСНачальнымРазделителем = "/часть1";
МассивВключаяПустые2 = СтрРазделить(СтрокаСНачальнымРазделителем, Разделитель, Истина);
// Результат: {"", "часть1"}
Сообщить("Массив с начальным разделителем: " + СтрСоединить(МассивВключаяПустые2, "|"));
СтрокаСКонечнымРазделителем = "часть1/";
МассивВключаяПустые3 = СтрРазделить(СтрокаСКонечнымРазделителем, Разделитель, Истина);
// Результат: {"часть1", ""}
Сообщить("Массив с конечным разделителем: " + СтрСоединить(МассивВключаяПустые3, "|"));
У функции РазложитьСтрокуВМассивПодстрок() (из БСП) есть аналогичный параметр <ПропускатьПустыеСтроки>.
Если установить этот параметр в Истина, пустые строки не будут добавлены в результирующий массив. При использовании этой функции важно внимательно читать ее описание в вашей конфигурации, так как поведение по умолчанию или взаимодействие с другими параметрами (например, СокращатьНепечатаемыеСимволы) может иметь свои особенности.
// Предполагаем, что функция СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок доступна
СтрокаСПустыми = "часть1;;часть2";
Разделитель = ";";
// Включаем пустые подстроки (параметр Ложь или Неопределено в зависимости от реализации)
МассивВключаяПустые = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СтрокаСПустыми, Разделитель, Ложь);
// Результат: {"часть1", "", "часть2"}
Сообщить("Массив БСП включая пустые: " + СтрСоединить(МассивВключаяПустые, "|"));
// Исключаем пустые подстроки
МассивБезПустых = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СтрокаСПустыми, Разделитель, Истина);
// Результат: {"часть1", "часть2"}
Сообщить("Массив БСП без пустых: " + SтрСоединить(МассивБезПустых, "|"));
Правильное управление этим параметром позволяет избежать неожиданного поведения и упростить дальнейшую обработку полученного массива, делая ваш код более чистым, предсказуемым и надежным.