Работа со строками в 1С:Предприятие — одна из самых частых задач, с которыми сталкиваются разработчики.hether вы парсите CSV-файлы, обрабатываете JSON-ответы от API или просто делите текст на части по разделителю — умение правильно разбирать строки экономит часы отладки. Но если в обычном встроенном языке есть готовые функции вроде СтрРазделить() или ПолучениеСтрок(), то в запросах 1С всё не так очевидно.
В этой статье разберём 5 рабочих способов разделения строк прямо в SQL-запросах 1С 8.3, включая обходные пути для старых версий платформы, обработку многобайтовых кодировок (например, UTF-8) и нюансы работы с большими текстами. Особое внимание уделим разделению строк с учетом экранированных символов — это частая причина ошибок при импорте данных из внешних источников.
1. Стандартные функции 1С для разделения строк
Начнём с базовых инструментов, которые предлагает сама платформа. В большинстве случаев для простых задач хватит встроенных методов:
- 🔹
СтрРазделить(Строка, Разделитель)— возвращает массив строк, разделённых указанным символом (или подстрокой). Работает только во встроенном языке, но не в SQL-запросах. - 🔹
СтрЧислоВхождений(Подстрока, Строка)— помогает посчитать количество разделителей перед разбором. - 🔹
Лев(Строка, Длина)/Прав(Строка, Длина)— для извлечения частей строки по фиксированной длине. - 🔹
СтрЗаменить(Строка, Старое, Новое)— полезно для предварительной очистки данных (например, замены двойных пробелов).
Пример использования СтрРазделить() во встроенном языке:
МассивСтрок = СтрРазделить("яблоко,банан,груша", ",");
Для Каждого Элемент Из МассивСтрок Цикл
Сообщить(Элемент);
КонецЦикла;
⚠️ Внимание: В SQL-запросах 1С эти функции недоступны! Их можно использовать только в коде модулей или при пост-обработке результатов запроса.
Если вам нужно разделить строку прямо в запросе, придётся использовать другие подходы — о них поговорим далее.
2. Разделение строк в SQL-запросах 1С: обходные пути
В отличие от встроенного языка, язык запросов 1С не имеет специализированных функций для работы со строками. Однако есть несколько трюков:
- 🔧 Использование
ПОДСТРОКА— для извлечения частей строки по позициям. Например, чтобы получить первые 5 символов:ЛЕВ(Поле, 5). - 🔧 Поиск позиций разделителя через
НАЙТИилиПОЗИЦИЯ, а затем обрезка строки. - 🔧 Рекурсивные запросы (для сложных случаев) — позволяют разбирать строки с вложенными разделителями.
Пример запроса, который извлекает первую часть строки до запятой:
ВЫБРАТЬ
ЛЕВ(ТекстовоеПоле, НАЙТИ(ТекстовоеПоле, ",") - 1) КАК ПерваяЧасть
ИЗ
Документ.МойДокумент
Для более сложных сценариев (например, разделение на несколько частей) можно использовать временные таблицы или виртуальные таблицы с предварительной обработкой данных.
3. Регулярные выражения для сложных разделителей
Когда строка имеет нестандартный формат (например, данные в кавычках, экранированные символы или несколько разделителей подряд), на помощь приходят регулярные выражения. В 1С 8.3.10+ они поддерживаются через объект РегулярноеВыражение.
Пример разбора строки с регулярками:
РегВыр = Новый РегулярноеВыражение("""([^""])""\s,\s*""([^""]*)""");
Результат = РегВыр.ВыполнитьПоиск('"Иванов";"Петр";"Сергеевич"');
Если Результат.Найдено Тогда
Сообщить(Результат.Группа(1)); // Иванов
Сообщить(Результат.Группа(2)); // Петр
КонецЕсли;
Для использования регулярных выражений внутри запроса придётся создать виртуальную таблицу или использовать ВЫРАЗИТЬ с предварительной обработкой.
⚠️ Внимание: Регулярные выражения в 1С работают медленнее встроенных функций. Не используйте их для обработки больших объёмов данных (свыше 10 000 строк) без оптимизации.
Если вам нужно разделить строку по нескольким разделителям (например, запятая или точка с запятой), используйте регулярное выражение с группой символов: [,;]
4. Разделение строк с учетом экранированных символов
Одна из самых сложных задач — разбор строк, где разделители могут быть экранированы (например, CSV-файлы с полями в кавычках). Типичный пример:
"Иванов, Иван""Иванович";"Москва; ул. Ленина, д.1"
Здесь запятые и точки с запятой внутри кавычек не должны считаться разделителями. Для такого случая алгоритм будет следующим:
- Пройти по строке символ за символом.
- Отслеживать, находимся ли мы внутри кавычек (флаг
ВнутриКавычек). - Разделять строку только по неэкранированным разделителям.
Пример кода для обработки такого случая:
Функция РазделитьСЭкранированием(Строка, Разделитель)
Результат = Новый Массив;
ТекущаяЧасть = "";
ВнутриКавычек = Ложь;
Для Инд = 1 По СтрДлина(Строка) Цикл
Символ = Сред(Строка, Инд, 1);
Если Символ = """" Тогда
ВнутриКавычек = Не ВнутриКавычек;
ИначеЕсли Символ = Разделитель И Не ВнутриКавычек Тогда
Результат.Добавить(ТекущаяЧасть);
ТекущаяЧасть = "";
Продолжить;
КонецЕсли;
ТекущаяЧасть = ТекущаяЧасть + Символ;
КонецЦикла;
Если ТекущаяЧасть <> "" Тогда
Результат.Добавить(ТекущаяЧасть);
КонецЕсли;
Возврат Результат;
КонецФункции;
Что будет, если не учитывать экранирование?
Без обработки кавычек строка '"Иванов, Иван""Иванович";"Москва"' разобьётся на 4 части вместо двух:
- "Иванов
- Иван"Иванович"
- "Москва"
- пустая строка
5. Разделение строк в больших данных: оптимизация производительности
При работе с большими объёмами данных (например, импорт CSV-файла на 100 000 строк) стандартные методы могут тормозить. В таких случаях:
- 🚀 Используйте пакетную обработку — разбивайте данные на порции по 1 000–5 000 строк.
- 🚀 Отключайте транзакционность на время массовой загрузки (если это допустимо).
- 🚀 Применяйте временные таблицы для промежуточных результатов.
- 🚀 Для CSV используйте специализированные обработки (например, ЧтениеCSV из библиотеки OneScript).
Пример оптимизированного кода для пакетного разделения:
Процедура ОбработатьБольшойФайл(ПутьКФайлу)
Текст = Новый ЧтениеТекста(ПутьКФайлу);
Пачка = Новый Массив;
Счетчик = 0;
Пока Текст.ПрочитатьСтроку() Цикл
Пачка.Добавить(РазделитьСтроку(Текст.ТекущаяСтрока));
Счетчик = Счетчик + 1;
Если Счетчик >= 1000 Тогда
ЗаписатьПачкуВБазу(Пачка);
Пачка.Очистить();
Счетчик = 0;
КонецЕсли;
КонецЦикла;
Если Пачка.Количество() > 0 Тогда
ЗаписатьПачкуВБазу(Пачка);
КонецЕсли;
КонецПроцедуры;
| Метод | Скорость | Сложность реализации | Подходит для больших данных |
|---|---|---|---|
СтрРазделить() |
Средняя | Низкая | Нет |
SQL-запросы с ПОДСТРОКА |
Высокая | Средняя | Да (с ограничениями) |
| Регулярные выражения | Низкая | Высокая | Нет |
| Пакетная обработка | Очень высокая | Высокая | Да |
6. Типичные ошибки и как их избежать
Даже опытные разработчики иногда сталкиваются с проблемами при разделении строк. Вот самые распространённые ошибки:
- ❌ Игнорирование пустых элементов — если строка заканчивается разделителем (например,
"a,b,c,"), последний элемент может потеряться. - ❌ Неучёт многобайтовых символов — функции вроде
Сред()работают с байтами, а не с символами в UTF-8. - ❌ Переполнение памяти при обработке очень длинных строк (свыше 10 МБ).
- ❌ Неправильная обработка переносов строк (например,
\r\nvs\n).
Чтобы избежать этих проблем:
⚠️ Внимание: Всегда проверяйте результат разделения на крайние случаи: пустые строки, строки только с разделителями, строки с экранированными символами. Используйте модульные тесты!
☑️ Проверка корректности разделения строк
7. Практический пример: разбор CSV в 1С
Рассмотрим полный пример загрузки CSV-файла с разделением строк и записью в справочник Номенклатура.
Исходный файл goods.csv:
"Артикул","Наименование","Цена"
"ART001","Стул офисный","1500.50"
"ART002","Стол письменный; большой","3200.00"
Код обработки:
Процедура ЗагрузитьCSV(ПутьКФайлу)
// 1. Чтение файла
Текст = Новый ЧтениеТекста(ПутьКФайлу);
Разделитель = ",";
// 2. Пропускаем заголовок
Текст.ПрочитатьСтроку();
// 3. Обрабатываем строки
Пока Текст.ПрочитатьСтроку() Цикл
Данные = РазделитьСЭкранированием(Текст.ТекущаяСтрока, Разделитель);
НоваяНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
НоваяНоменклатура.Артикул = Данные[0];
НоваяНоменклатура.Наименование = Данные[1];
НоваяНоменклатура.Цена = Число(Данные[2]);
НоваяНоменклатура.Записать();
КонецЦикла;
КонецПроцедуры;
Обратите внимание на использование кастомной функции РазделитьСЭкранированием() из предыдущего раздела — она корректно обработает точку с запятой в наименовании товара.
Для CSV-файлов всегда проверяйте первую строку на наличие заголовков и кодировку (ANSI/UTF-8). В 1С для чтения UTF-8 используйте ЧтениеТекста с параметром КодировкаТекста.UTF8.
FAQ: Частые вопросы по разделению строк в 1С
Можно ли разделить строку прямо в запросе 1С без пост-обработки?
В чистом SQL-запросе 1С нет встроенных функций для разделения строк на массивы. Однако можно:
- Использовать
ПОДСТРОКАдля извлечения первой/последней части. - Создать виртуальную таблицу с предварительно разделёнными данными.
- Применить рекурсивный запрос (для простых случаев).
Для сложных сценариев лучше разделять строки во встроенном языке после выполнения запроса.
Как разделить строку по нескольким разделителям (например, запятая или точка с запятой)?
Есть два подхода:
- Последовательная замена:
Строка = СтрЗаменить(Строка, ";", ",");Массив = СтрРазделить(Строка, ",");
- Регулярное выражение:
РегВыр = Новый РегулярноеВыражение("[,;]");Результат = РегВыр.Разбить("a,b;c,d");
Почему функция СтрРазделить() неправильно работает с кириллицей?
Проблема возникает из-за неверной кодировки исходной строки. Например, если строка в UTF-8, а 1С ожидает ANSI, символы кириллицы могут "разбиваться" на несколько байт, что приводит к ошибкам при разделении.
Решение:
// Преобразуем строку в UTF-8 перед разделением
Текст = СтрокаДляUTF8(ИсходнаяСтрока);
Массив = СтрРазделить(Текст, ",");
Как разделить строку на части фиксированной длины?
Используйте комбинацию функций ЛЕВ(), ПРАВ() и СРЕД(). Пример для разделения на части по 10 символов:
Для Инд = 1 По СтрДлина(Строка) / 10 Цикл
Часть = Сред(Строка, (Инд - 1) * 10 + 1, 10);
Сообщить(Часть);
КонецЦикла;
Для последней части проверьте остаток от деления длины строки на 10.
Можно ли использовать Split() как в других языках программирования?
В 1С нет прямого аналога Split() из JavaScript или Python, но функциональность полностью покрывается:
СтрРазделить()— для простых случаев.РегулярноеВыражение.Разбить()— для сложных шаблонов.- Кастомные функции — для специфических задач (например, с экранированием).