Как получить из строки массив отдельных слов в 1С
Содержание
Чтобы получить из строки массив отдельных слов, в 1С 8.3 чаще всего хватает одной строки кода: СтрРазделить(Текст, " ", Ложь). Функция вернёт массив, где каждый элемент — слово, а третий параметр Ложь отбросит пустые элементы, которые иначе появляются на месте двойных пробелов.
Проблема в том, что в реальном тексте слова отделяются не только пробелом. Там бывают запятые, точки, табуляция, переносы строк и неразрывные пробелы из выгрузок и копипаста. Поэтому кроме быстрого способа разберём ещё три: перебор символов в цикле, регулярные выражения для сложных шаблонов и предварительную чистку строки. В конце — таблица «что быстрее» и когда какой способ брать.
Способы отличаются не результатом, а гибкостью: СтрРазделить закрывает 90% задач, ручной цикл нужен, когда разбор нестандартный, а регулярные выражения — когда разделителем служит целый шаблон, а не отдельные символы.
СтрРазделить(Текст, " ,;", Ложь) — одна строка, самый быстрый вариант.Функция СтрРазделить — основной инструмент
СтрРазделить появилась в платформе 8.3.6 и с тех пор есть в любой актуальной конфигурации на управляемых формах. Синтаксис:
СтрРазделить(<Строка>, <Разделитель>, <ВключатьПустые>)
- Строка — исходный текст.
- Разделитель — строка, причём каждый символ этой строки считается отдельным разделителем. Это ключевой момент: если передать
" ,;", функция разобьёт текст по пробелу, запятой или точке с запятой за один проход. - ВключатьПустые — булево. По умолчанию
Истина: на месте двух разделителей подряд в массив попадёт пустая строка. Чтобы выбросить пустышки, передавайтеЛожь.
Простой разбор по пробелам:
Текст = "Приходная накладная от поставщика";
Слова = СтрРазделить(Текст, " ", Ложь);
// Слова[0] = "Приходная", Слова[1] = "накладная", ... Слова.Количество() = 4
Разбор по нескольким разделителям сразу — пробел, запятая, точка, точка с запятой:
Текст = "яблоко, груша; слива.виноград";
Разделители = " ,.;";
Слова = СтрРазделить(Текст, Разделители, Ложь);
// Четыре элемента: "яблоко", "груша", "слива", "виноград"
Если нужно собрать слова обратно в строку, парная функция — СтрСоединить(Массив, " "). Она склеит элементы массива через указанный разделитель.
Табуляцию и перенос строки тоже можно добавить в список разделителей через системное перечисление Символы:
Разделители = " " + Символы.Таб + Символы.ПС + Символы.ВК;
Слова = СтрРазделить(Текст, Разделители, Ложь);
Здесь Символы.ПС — перевод строки, Символы.ВК — возврат каретки, Символы.Таб — табуляция. Такой набор разделителей корректно разбирает многострочный текст, вставленный из Excel или письма.
Ручной разбор строки в цикле
Перебор символов нужен, когда стандартного разбиения мало: вы хотите считать слова на ходу, сохранять сами разделители, прерывать разбор по условию или работаете на старой платформе, где СтрРазделить ещё нет.
Идея простая: идём по строке символ за символом с помощью Сред, накапливаем буфер и, встретив разделитель, сбрасываем накопленное слово в массив.
Функция РазбитьНаСлова(Текст)
Слова = Новый Массив;
Буфер = "";
Для Позиция = 1 По СтрДлина(Текст) Цикл
Символ = Сред(Текст, Позиция, 1);
Если Символ = " " Тогда
Если НЕ ПустаяСтрока(Буфер) Тогда
Слова.Добавить(Буфер);
Буфер = "";
КонецЕсли;
Иначе
Буфер = Буфер + Символ;
КонецЕсли;
КонецЦикла;
// не забываем последнее слово — после него может не быть пробела
Если НЕ ПустаяСтрока(Буфер) Тогда
Слова.Добавить(Буфер);
КонецЕсли;
Возврат Слова;
КонецФункции
Здесь задействованы СтрДлина (длина строки), Сред(Строка, Начало, Количество) (вырезать подстроку) и ПустаяСтрока (проверка на пустоту с учётом пробелов). Двойные пробелы обрабатываются сами собой: пустой буфер в массив не попадает.
Если разделитель всегда один и тот же, быстрее искать его сразу функцией СтрНайти, а не перебирать каждый символ. СтрНайти(Остаток, " ") вернёт позицию первого пробела, а Лев и Сред отрежут слово и остаток строки. Логика та же, но итераций меньше.
У ручного способа есть расплата за гибкость. В 1С строки неизменяемые, и выражение Буфер = Буфер + Символ на каждом шаге создаёт новую строку. На тексте в сотни тысяч символов это заметно тормозит. Для больших объёмов берите СтрРазделить — она выполняется в ядре платформы и работает в разы быстрее.
Регулярные выражения для сложных шаблонов
Когда разделитель — не фиксированный символ, а шаблон (например, «любая последовательность не-букв» или «слова, начинающиеся с цифры»), на помощь приходят регулярные выражения.
Встроенный объект регулярных выражений доступен в платформе не ниже 8.3.23. На более старых платформах его нет, и внешние COM-компоненты для этого лучше не тянуть — надёжнее остаться на СтрРазделить или ручном переборе.
Шаблон [0-9A-Za-zА-Яа-яЁё]+ описывает «одно или несколько подряд идущих буквенно-цифровых символов» — то есть слово. Всё, что между такими группами (пробелы, знаки препинания), считается разделителем автоматически:
РегВыр = Новый РегулярноеВыражение("[0-9A-Za-zА-Яа-яЁё]+");
РегВыр.ИгнорироватьРегистр = Истина;
Слова = Новый Массив;
Для Каждого Совпадение Из РегВыр.НайтиСовпадения(Текст) Цикл
Слова.Добавить(Совпадение.Значение);
КонецЦикла;
Метод НайтиСовпадения возвращает коллекцию найденных фрагментов, а свойство Значение каждого элемента — сам текст слова. Такой подход удобен тем, что не требует перечислять все возможные разделители: вы описываете, как выглядит слово, а не чем оно отделено.
Точные имена методов и поддерживаемый синтаксис шаблонов смотрите в синтакс-помощнике вашей платформы — набор возможностей регулярных выражений от версии к версии расширяется.
Чистим строку перед разбором
Половина проблем с разбором — не в коде, а во входных данных. Строки из выгрузок, писем и внешних систем приходят с «мусором», который ломает простое разбиение по пробелу.
Типичные загрязнители и чем их убрать:
- 🔹 Пробелы по краям —
СокрЛП(Текст)обрезает их слева и справа. - 🔹 Неразрывные пробелы (частый гость из Word и выгрузок) — заменяем на обычный:
СтрЗаменить(Текст, Символы.НПП, " "). - 🔹 Табуляция и переносы — либо добавляем в разделители, либо заменяем на пробел тем же
СтрЗаменить. - 🔹 Разный регистр — если слова потом сравниваются, приведите всё к одному регистру через
НРег(нижний) илиВРег(верхний).
Небольшая функция подготовки строки перед разбором:
Функция ПодготовитьТекст(Текст)
Результат = СокрЛП(Текст);
Результат = СтрЗаменить(Результат, Символы.НПП, " ");
Результат = СтрЗаменить(Результат, Символы.Таб, " ");
Результат = СтрЗаменить(Результат, Символы.ПС, " ");
Возврат Результат;
КонецФункции
После такой чистки хватает самого простого СтрРазделить(ПодготовитьТекст(Текст), " ", Ложь): двойные и тройные пробелы, оставшиеся от замен, параметр Ложь отбросит сам.
Не нормализуйте там, где не нужно. Если слова потом пойдут в сравнение по точному значению (артикулы, коды), менять регистр нельзя — потеряете различие между АБВ и абв.
Крайние случаи: пустые значения и неожиданный тип
Код, который работает на «хорошей» строке, падает на реальных данных. Разберём, что подстелить.
Неопределено и Null. Поля из базы приходят не только строками. Реквизит может быть Неопределено, а значение из запроса — Null. Передавать их в строковые функции нельзя — будет ошибка. Поэтому первой строкой проверяйте заполненность:
Если НЕ ЗначениеЗаполнено(Текст) Тогда
Возврат Новый Массив; // пустой результат вместо ошибки
КонецЕсли;
ЗначениеЗаполнено вернёт Ложь и для пустой строки, и для Неопределено, и для Null — одна проверка на все три случая.
Строка из одних разделителей. Текст вида " " или ",,," после разбора с параметром Ложь даёт пустой массив — это корректно, но вызывающий код должен быть готов к нулевому количеству слов.
Разделители по краям. Ведущий или замыкающий пробел (" слово ") при ВключатьПустые = Ложь не создаёт лишних элементов. А вот при Истина — создаёт, поэтому для разбора на слова почти всегда нужен именно Ложь.
Частые причины «странного» результата:
- ❌ В массиве появились пустые строки — забыли передать третий параметр
Ложь(по умолчанию онИстина). - ❌ Слова «слиплись» — в разделителях не учли запятую, точку или перенос строки.
- ❌ Ошибка при вызове функции — на вход пришло
НеопределеноилиNullбез проверкиЗначениеЗаполнено. - ❌ Регулярное выражение «не находит» слова — платформа старше 8.3.23, где объекта ещё нет.
Практический пример: разобрать ФИО на части
Разбор на слова чаще всего нужен не ради массива, а чтобы вытащить из него конкретные элементы. Классика — разложить ФИО из одного поля на фамилию, имя и отчество.
ФИО = СокрЛП("Иванов Пётр Сергеевич");
Части = СтрРазделить(ФИО, " ", Ложь);
Фамилия = ?(Части.Количество() > 0, Части[0], "");
Имя = ?(Части.Количество() > 1, Части[1], "");
Отчество = ?(Части.Количество() > 2, Части[2], "");
Обратите внимание на две детали. Во-первых, СокрЛП снимает краевые пробелы, а Ложь гасит двойной пробел в середине — иначе Части[1] оказался бы пустым. Во-вторых, перед обращением к элементу по индексу всегда проверяйте Количество(): отчество в России есть не у всех, и жёсткое обращение к Части[2] на строке из двух слов вызовет ошибку выхода за границу массива.
Тот же приём работает для адресов, артикулов с пробелами, строк «ключ значение» из настроек — разбиваете на части, а дальше берёте нужные по индексу с проверкой количества.
Что быстрее и когда что брать
Для коротких строк разница незаметна, но на пакетной обработке или больших текстах способ выбирают по скорости и задаче.
| Способ | Когда применять | Скорость | Ограничения |
|---|---|---|---|
СтрРазделить | Разделители — отдельные символы (пробел, запятая, перенос) | Высокая | Разделитель нельзя задать шаблоном |
| Перебор в цикле | Нужна своя логика, подсчёт на ходу, старая платформа | Низкая на больших строках | Конкатенация в цикле тормозит |
СтрНайти + Лев/Сред | Один фиксированный разделитель, поиск по позициям | Средняя | Код длиннее, легко ошибиться в индексах |
| Регулярное выражение | Разделитель — шаблон, сложные правила «что есть слово» | Средняя (есть компиляция шаблона) | Только платформа не ниже 8.3.23 |
Практический вывод короткий: начинайте со СтрРазделить. Переходите на цикл или СтрНайти только тогда, когда стандартного разбиения действительно не хватает, а к регулярным выражениям — когда разделителем служит шаблон, а не набор символов.
Частые вопросы
Чем `СтрРазделить` отличается от `СтрНайти`?
СтрРазделить сразу возвращает массив всех фрагментов, а СтрНайти — только позицию одного вхождения подстроки. Для разбора на слова удобнее СтрРазделить; СтрНайти берут, когда нужно найти конкретный разделитель и работать с позициями вручную.Можно ли задать несколько разделителей в одном вызове?
СтрРазделить каждый символ строки-разделителя считается отдельным разделителем. Передали " ,;" — текст разобьётся по пробелу, запятой и точке с запятой за один проход.Почему в результате появляются пустые строки?
ВключатьПустые по умолчанию равен Истина, и на месте двух разделителей подряд в массив попадает пустой элемент. Передайте Ложь, чтобы пустышки отбрасывались.