Как получить из строки массив отдельных слов в 1С

· 9 мин

Содержание

Чтобы получить из строки массив отдельных слов, в 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

Практический вывод короткий: начинайте со СтрРазделить. Переходите на цикл или СтрНайти только тогда, когда стандартного разбиения действительно не хватает, а к регулярным выражениям — когда разделителем служит шаблон, а не набор символов.

Частые вопросы

Чем `СтрРазделить` отличается от `СтрНайти`?
СтрРазделить сразу возвращает массив всех фрагментов, а СтрНайти — только позицию одного вхождения подстроки. Для разбора на слова удобнее СтрРазделить; СтрНайти берут, когда нужно найти конкретный разделитель и работать с позициями вручную.
Можно ли задать несколько разделителей в одном вызове?
Да. В СтрРазделить каждый символ строки-разделителя считается отдельным разделителем. Передали " ,;" — текст разобьётся по пробелу, запятой и точке с запятой за один проход.
Почему в результате появляются пустые строки?
Третий параметр ВключатьПустые по умолчанию равен Истина, и на месте двух разделителей подряд в массив попадает пустой элемент. Передайте Ложь, чтобы пустышки отбрасывались.
Как сохранить знаки препинания при разборе?
Стандартное разбиение их теряет. Если точки и запятые нужно оставить привязанными к словам, пишите перебор символов в цикле или подберите регулярное выражение, которое включает нужные символы в шаблон слова.
Работает ли `СтрРазделить` на тонком и веб-клиенте?
Да, это общий метод встроенного языка, доступный на клиенте и на сервере во всех актуальных конфигурациях на управляемых формах.