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

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

В практике разработки на платформе 1С часто возникает задача нормализации данных. Одной из типичных ситуаций является получение строк, где слова написаны слитно, но каждое новое слово начинается с заглавной буквы (так называемый CamelCase). Чаще всего это встречается при импорте данных из внешних систем или некорректном вводе ФИО, например, ИванИванович. Наша задача — превратить это в читаемое Иван Иванович.

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

Вариант 1. Простой перебор символов в цикле

Начнем с самого очевидного способа. Рассмотрим алгоритм, который проходит по всей строке символ за символом и проверяет регистр каждого знака. Если символ является заглавным, мы добавляем перед ним пробел.

Проанализируем простую функцию, реализующую этот подход:


Функция ПреобразоватьТРег(СтрокаИсточник)
    Результат = "";
    Для Сч = 1 По СтрДлина(СтрокаИсточник) Цикл
        Символ = Сред(СтрокаИсточник, Сч, 1);
        // Сравниваем символ с его вариантом в верхнем регистре
        Если Символ = ВРег(Символ) И Сч > 1 Тогда 
            Результат = Результат + " " + Символ;
        Иначе
            Результат = Результат + Символ;
        КонецЕсли;
    КонецЦикла;
    Возврат СокрЛП(Результат);
КонецФункции

Разберем, как работает этот код. Мы используем функцию Сред() для извлечения каждого конкретного знака. Главное условие здесь — Символ = ВРег(Символ). Если оно истинно, значит, перед нами заглавная буква. Обратите внимание на условие Сч > 1: оно необходимо, чтобы не поставить лишний пробел в самом начале строки, если первое слово начинается с большой буквы.

Важное замечание: этот метод имеет недостаток. Если в строке встретятся цифры или знаки пунктуации, функция ВРег() вернет тот же самый символ, и условие сработает ложно (перед цифрой добавится пробел). Для простых ФИО это приемлемо, но для сложных данных стоит поискать другое решение.

Вариант 2. Оптимизированный поиск первой заглавной буквы

Если мы точно знаем, что в строке всего два слова (например, только Имя и Отчество), мы можем оптимизировать код, прервав цикл после нахождения первого разделителя. Это работает быстрее на больших объемах данных.


Процедура РазделитьДваСлова(СтрСлитная)
    ПозицияРаздела = 0;
    // Начинаем со второго символа, так как первый всегда заглавный
    Для Й = 2 По СтрДлина(СтрСлитная) Цикл
        Символ = Сред(СтрСлитная, Й, 1);
        Если Символ = ВРег(Символ) Тогда
            ПозицияРаздела = Й;
            Прервать; // Выходим из цикла, как только нашли заглавную букву
        КонецЕсли;
    КонецЦикла;

    Если ПозицияРаздела > 0 Тогда
        СтрСПробелом = Лев(СтрСлитная, ПозицияРаздела - 1) + " " + Сред(СтрСлитная, ПозицияРаздела);
    Иначе
        СтрСПробелом = СтрСлитная;
    КонецЕсли;
    
    Сообщить(СтрСПробелом);
КонецПроцедуры

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

Вариант 3. Продвинутый метод с использованием кодов символов и СтрРазделить

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

Разберем по шагам реализацию этой функции:


Функция РазделитьЧастиКириллическогоФИО(Знач СлитноеФио) Экспорт
    // Вычисляем смещение между А и а в таблице символов
    СмещениеДоНР = КодСимвола("а") - КодСимвола("А"); 
    
    // Шаг 1: Подготавливаем строку. Заменяем "И" на "Ии", "С" на "Сс" и т.д.
    Для тКодВР = КодСимвола("А") По КодСимвола("Я") Цикл
        Заглавная = Символ(тКодВР);
        Строчная = Символ(тКодВР + СмещениеДоНР);
        СлитноеФио = СтрЗаменить(СлитноеФио, Заглавная, Заглавная + Строчная);
    КонецЦикла;
    
    // Шаг 2: Используем СтрРазделить, где разделители — все заглавные буквы
    Разделители = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЬЪЭЮЯ";
    мЧастиФио = СтрРазделить(СлитноеФио, Разделители, Ложь);
    
    // Шаг 3: Собираем результат, очищая от лишних символов
    РезультатФИО = "";
    Для каждого тЧасть Из мЧастиФио Цикл
        Если ПустаяСтрока(тЧасть) Тогда Продолжить; КонецЕсли;
        РезультатФИО = РезультатФИО + тЧасть + " ";
    КонецЦикла;
    
    // Возвращаем результат в правильном регистре (Первая заглавная, остальные строчные)
    Возврат ТРег(СокрП(РезультатФИО));
КонецФункции

Почему это решение эффективно?

  1. Работа с цифрами: Функция СтрРазделить игнорирует цифры, так как их нет в строке Разделители. Они просто остаются внутри частей слов.
  2. Удвоение букв: Это хитрая техника. Поскольку СтрРазделить "съедает" сам символ-разделитель, мы заранее подставляем после каждой заглавной буквы её строчную копию, чтобы после разделения слово сохранило свою структуру.
  3. Корректный регистр: Финальная функция ТРег() приводит строку к каноническому виду (например, если на входе было "ИВанов", на выходе получится "Иванов").

Вариант 4. Применение регулярных выражений (RegExp)

Хотя в обсуждении на форуме этот метод не был подробно расписан, для программиста 1С важно знать о существовании объекта VBScript.RegExp. Это наиболее профессиональный способ разделения строк CamelCase.

Посмотрим на пример кода, который делает ту же работу одной строкой поиска:


РегВыражение = Новый COMОбъект("VBScript.RegExp");
РегВыражение.Global = Истина;
РегВыражение.Pattern = "([а-яё])([А-ЯЁ])"; // Ищем стык строчной и заглавной буквы
Стр = "КонстантинПетрович";
Результат = РегВыражение.Replace(Стр, "$1 $2"); // Вставляем пробел между ними

Этот метод считается самым быстрым и устойчивым к ошибкам. Он находит место, где маленькая буква граничит с большой, и вставляет туда пробел, не трогая цифры, начало строки или аббревиатуры. Для упрощения работы с регулярными выражениями на платформе 1С подойдёт подсистема для работы с регулярными выражениями.

Рекомендации по выбору решения

Подводя итог нашему анализу, дадим несколько советов по выбору метода в зависимости от ситуации:

Выяснив причину возникновения проблемы и проанализировав доступные инструменты 1С, мы можем сделать вывод, что универсального "встроенного" метода для разделения слов по регистру не существует, но предложенные алгоритмы полностью закрывают эту потребность.

← На главную