Как получить первое слово из строки в 1С 8.3: разбираем все способы и исправляем ошибки

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке в среде 1С:Предприятие одной из частых задач является обработка текстовой информации. Например, нам может потребоваться выделить фамилию из полного ФИО, получить первое слово из наименования номенклатуры или отсечь лишние характеристики, оставив только главное название. На первый взгляд задача кажется тривиальной, однако при её реализации программисты часто допускают критические ошибки, которые приводят к сбоям в работе программы на реальных данных.

В этой статье мы подробно рассмотрим, как правильно решить задачу получения первого слова (до первого пробела) в 1С 8.3. Мы разберем как базовые методы, предложенные на форуме, так и профессиональные подходы, учитывающие потенциальные уязвимости («краевые случаи»), использование функций БСП (Библиотеки Стандартных Подсистем) и даже регулярных выражений.

Способ 1. Классический поиск через СтрНайти и Лев

Рассмотрим самое простое и популярное решение, основанное на комбинации встроенных функций платформы СтрНайти (находит позицию символа в строке) и Лев (вырезает подстроку заданной длины слева). На форуме было предложено следующее лаконичное решение:


КоличествоСимволовДоПробела = СтрНайти(Наименование, " ");
Наименование = Лев(Наименование, КоличествоСимволовДоПробела - 1);

Давайте проанализируем, как работает этот алгоритм. Функция СтрНайти по умолчанию ищет символ пробела слева направо. Если в строке Наименование записано значение "Наша новая номенклатура", функция вернет число 5 (индекс первого пробела). Далее функция Лев вырежет из строки 5 минус 1, то есть 4 символа слева. В результате мы получим корректное слово "Наша".

А как быть, если нам нужно найти не первый, а, к примеру, второй пробел? Разберем по шагам логику, предложенную участниками форума:


ПервыйПробел = СтрНайти(ТутСтрокаНаименование, " "); 
// Ищем второй пробел, начиная поиск с позиции сразу за первым пробелом
ВторойПробел = СтрНайти(ТутСтрокаНаименование, " ", , ПервыйПробел + 1); 

Здесь используется четвертый параметр функции СтрНайти, который указывает платформе, с какой именно позиции в строке следует начинать поиск. Это очень удобно для последовательного обхода строки.

Внимание: Опасность «краевых случаев» и исправление ошибок

Несмотря на простоту, приведенный выше код таит в себе серьезную опасность для стабильности системы. Выясним причину возможных падений базы в реальных условиях эксплуатации:

  1. Строка начинается с пробела (лидирующие пробелы). Если пользователь случайно ввел наименование как " Наша номенклатура" (с пробелом в самом начале), то СтрНайти вернет 1. При вычислении Лев(Строка, 1 - 1) мы получим пустую строку вместо первого слова.
  2. В строке вообще нет пробелов (одно слово). Если реквизит содержит значение "Номенклатура", то функция СтрНайти вернет 0. При попытке выполнить Лев(Строка, 0 - 1) мы передадим во второй параметр отрицательное число (-1). Платформа 1С в этом случае выдаст критическую ошибку выполнения (Runtime error): «Недопустимое значение параметра 2», и работа сеанса пользователя будет прервана.

Чтобы избежать подобных уязвимостей, мы должны всегда предварительно очищать обрабатываемую строку от лишних пробелов по краям с помощью функции СокрЛП (или СокрЛ), а также обязательно добавлять проверку на то, был ли пробел вообще найден в строке. Безопасный вариант кода будет выглядеть следующим образом:


ОчищеннаяСтрока = СокрЛП(ИсходнаяСтрока);
ПозицияПробела = СтрНайти(ОчищеннаяСтрока, " ");

Если ПозицияПробела > 0 Тогда
    ПервоеСлово = Лев(ОчищеннаяСтрока, ПозицияПробела - 1);
Иначе
    // Если пробелов нет, значит вся строка состоит из одного слова
    ПервоеСлово = ОчищеннаяСтрока;
КонецЕсли;

Этот код надежен, стабилен и гарантированно не вызовет аварийного завершения работы программы, независимо от того, какие данные ввел пользователь.

Способ 2. Использование функции СтрРазделить

Начиная с версии платформы 8.3.6, разработчикам доступна крайне удобная функция СтрРазделить, которая разбивает исходную строку на массив подстрок по указанному разделителю. На форуме предложили элегантную однострочную конструкцию:


Функция ПервоеСловоДорожеВторого(Слова)
    Возврат СтрРазделить(Слова, " ").Получить(0);
КонецФункции

Давайте разберем по шагам, как это работает, и с какими подводными камнями мы можем здесь столкнуться. Метод СтрРазделить принимает строку и символ-разделитель (в нашем случае пробел " "), после чего возвращает объект типа Массив. Метод массива Получить(0) извлекает самый первый элемент (индексация элементов в 1С начинается с нуля).

В чем заключается проблема данного варианта?

Если между словами в строке будет стоять два или более пробелов подряд (например, "Наша новая номенклатура"), либо если пробел будет стоять в самом начале строки, функция СтрРазделить по умолчанию создаст в результирующем массиве пустые элементы со значением "". В итоге вызов Получить(0) вернет нам пустую строку вместо реального слова.

Для решения этой проблемы мы должны использовать третий параметр функции СтрРазделить — ВключатьПустые. По умолчанию он имеет значение Истина. Если же мы принудительно передадим туда значение Ложь, платформа сама проигнорирует дублирующиеся пробелы и не будет засорять массив пустыми строками. Дополнительно применим функцию СокрЛП:


// Очищаем строку от краевых пробелов и разбиваем ее, исключая пустые элементы
МассивСлов = СтрРазделить(СокрЛП(Слова), " ", Ложь);

Если МассивСлов.Количество() > 0 Тогда
    ПервоеСлово = МассивСлов[0]; // Альтернативный вариант получения первого элемента
Иначе
    ПервоеСлово = "";
КонецЕсли;

Способ 3. Готовые механизмы БСП (Библиотека Стандартных Подсистем)

Если вы работаете в современной типовой конфигурации 1С (такой как ERP, Управление торговлей, Бухгалтерия предприятия или ЗУП), то писать собственные велосипеды для парсинга строк нет никакой необходимости. В составе БСП есть мощный общий модуль СтроковыеФункцииКлиентСервер, содержащий протестированные и оптимизированные функции на все случаи жизни.

Рассмотрим два наиболее полезных метода из этого модуля.

Вариант А: РазложитьСтрокуВМассивПодстрок

Этот метод работает аналогично СтрРазделить, но корректно обрабатывает все тонкости и поддерживается даже на старых версиях платформы 1С.


МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Строка, " ", Истина, Истина);
ПервоеСлово = ?(МассивПодстрок.Количество() > 0, МассивПодстрок[0], "");

Здесь параметры функции указывают на необходимость сокращения пробелов и исключения пустых элементов из результирующего массива.

Вариант Б: РазложитьСтрокуВМассивСлов

Этот способ незаменим, если первым словом нужно считать подстроку, которая может отделяться от остальной части текста не только пробелом, но и любым другим небуквенным символом (например, запятой, точкой, дефисом, точкой с запятой или знаком подчеркивания). Функция автоматически распознает границы слов:


// Для строки "Наша,новая_номенклатура" вернет массив ["Наша", "новая", "номенклатура"]
МассивСлов = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов(Строка);
ПервоеСлово = ?(МассивСлов.Количество() > 0, МассивСлов[0], "");

Способ 4. Классический метод через замену разделителя

До появления в платформе 8.3 функции СтрРазделить, разработчики 1С часто использовали оригинальный и очень надежный прием. Идея заключается в том, чтобы временно заменить все пробелы в строке на символ перевода строки (Символы.ПС), превратив горизонтальную строку в многострочный текст. После этого можно легко извлечь первую строку. Посмотрим на реализацию:


// Очищаем строку и превращаем пробелы в переводы строк
ПреобразованныйТекст = СтрЗаменить(СокрЛП(ИсходнаяСтрока), " ", Символы.ПС);
// Извлекаем самую первую строку из получившегося многострочного текста
ПервоеСлово = СтрПолучитьСтроку(ПреобразованныйТекст, 1);

Данный метод примечателен тем, что он абсолютно универсален, работает на любых (даже самых древних) версиях платформы 1С и никогда не приводит к ошибкам выполнения, даже если пробелов в строке не было изначально.

Способ 5. Использование регулярных выражений (RegEx) для сложных задач

Иногда возникают нестандартные задачи. Например, когда первым словом нужно считать строго буквенную последовательность, полностью проигнорировав любые служебные символы, цифры или пробелы в начале текста. На стороне сервера под управлением ОС Windows мы можем задействовать COM-объект регулярных выражений:


RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Pattern = "^\s*([^\s]+)"; // Шаблон ищет первую группу непробельных символов
RegExp.IgnoreCase = Истина;
RegExp.Global = Ложь;

Matches = RegExp.Execute(ИсходнаяСтрока);
Если Matches.Count > 0 Тогда
    ПервоеСлово = Matches.Item(0).SubMatches.Item(0);
Иначе
    ПервоеСлово = "";
КонецЕсли;

Использование регулярных выражений — это мощный инструмент для продвинутой валидации и разбора сложных текстовых массивов, хотя для простых повседневных задач обычных функций платформы 1С бывает более чем достаточно.

Резюме и рекомендации

Мы проанализировали различные варианты решения задачи. Какой же способ выбрать для практического применения?

← На главную