В практике разработки на платформе 1С часто возникает задача нормализации данных. Одной из типичных ситуаций является получение строк, где слова написаны слитно, но каждое новое слово начинается с заглавной буквы (так называемый CamelCase). Чаще всего это встречается при импорте данных из внешних систем или некорректном вводе ФИО, например, ИванИванович. Наша задача — превратить это в читаемое Иван Иванович.
В данной статье мы разберем несколько подходов к решению этой задачи: от самых простых алгоритмов до продвинутых функций, учитывающих особенности кириллицы и наличие сторонних символов. При подготовке инструментов миграции для сопоставления объектов с несовпадающими ссылками применяется обработка переноса данных между похожими конфигурациями 1С.
Начнем с самого очевидного способа. Рассмотрим алгоритм, который проходит по всей строке символ за символом и проверяет регистр каждого знака. Если символ является заглавным, мы добавляем перед ним пробел.
Проанализируем простую функцию, реализующую этот подход:
Функция ПреобразоватьТРег(СтрокаИсточник)
Результат = "";
Для Сч = 1 По СтрДлина(СтрокаИсточник) Цикл
Символ = Сред(СтрокаИсточник, Сч, 1);
// Сравниваем символ с его вариантом в верхнем регистре
Если Символ = ВРег(Символ) И Сч > 1 Тогда
Результат = Результат + " " + Символ;
Иначе
Результат = Результат + Символ;
КонецЕсли;
КонецЦикла;
Возврат СокрЛП(Результат);
КонецФункции
Разберем, как работает этот код. Мы используем функцию Сред() для извлечения каждого конкретного знака. Главное условие здесь — Символ = ВРег(Символ). Если оно истинно, значит, перед нами заглавная буква. Обратите внимание на условие Сч > 1: оно необходимо, чтобы не поставить лишний пробел в самом начале строки, если первое слово начинается с большой буквы.
Важное замечание: этот метод имеет недостаток. Если в строке встретятся цифры или знаки пунктуации, функция ВРег() вернет тот же самый символ, и условие сработает ложно (перед цифрой добавится пробел). Для простых ФИО это приемлемо, но для сложных данных стоит поискать другое решение.
Если мы точно знаем, что в строке всего два слова (например, только Имя и Отчество), мы можем оптимизировать код, прервав цикл после нахождения первого разделителя. Это работает быстрее на больших объемах данных.
Процедура РазделитьДваСлова(СтрСлитная)
ПозицияРаздела = 0;
// Начинаем со второго символа, так как первый всегда заглавный
Для Й = 2 По СтрДлина(СтрСлитная) Цикл
Символ = Сред(СтрСлитная, Й, 1);
Если Символ = ВРег(Символ) Тогда
ПозицияРаздела = Й;
Прервать; // Выходим из цикла, как только нашли заглавную букву
КонецЕсли;
КонецЦикла;
Если ПозицияРаздела > 0 Тогда
СтрСПробелом = Лев(СтрСлитная, ПозицияРаздела - 1) + " " + Сред(СтрСлитная, ПозицияРаздела);
Иначе
СтрСПробелом = СтрСлитная;
КонецЕсли;
Сообщить(СтрСПробелом);
КонецПроцедуры
Здесь мы использовали функции Лев() и Сред() (в варианте с двумя параметрами) для "разрезания" строки в найденной позиции. Это более строгий подход, который исключает появление множественных пробелов, если слов в строке больше двух.
Теперь рассмотрим наиболее интересное и надежное решение, предложенное участниками сообщества. Этот метод решает проблему цифр и спецсимволов, работая прицельно с кириллическим алфавитом. Рассмотрим логику: мы сначала дублируем заглавные буквы их строчными копиями, а затем используем системную функцию СтрРазделить(), где в качестве разделителей выступает весь алфавит заглавных букв.
Разберем по шагам реализацию этой функции:
Функция РазделитьЧастиКириллическогоФИО(Знач СлитноеФио) Экспорт
// Вычисляем смещение между А и а в таблице символов
СмещениеДоНР = КодСимвола("а") - КодСимвола("А");
// Шаг 1: Подготавливаем строку. Заменяем "И" на "Ии", "С" на "Сс" и т.д.
Для тКодВР = КодСимвола("А") По КодСимвола("Я") Цикл
Заглавная = Символ(тКодВР);
Строчная = Символ(тКодВР + СмещениеДоНР);
СлитноеФио = СтрЗаменить(СлитноеФио, Заглавная, Заглавная + Строчная);
КонецЦикла;
// Шаг 2: Используем СтрРазделить, где разделители — все заглавные буквы
Разделители = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЬЪЭЮЯ";
мЧастиФио = СтрРазделить(СлитноеФио, Разделители, Ложь);
// Шаг 3: Собираем результат, очищая от лишних символов
РезультатФИО = "";
Для каждого тЧасть Из мЧастиФио Цикл
Если ПустаяСтрока(тЧасть) Тогда Продолжить; КонецЕсли;
РезультатФИО = РезультатФИО + тЧасть + " ";
КонецЦикла;
// Возвращаем результат в правильном регистре (Первая заглавная, остальные строчные)
Возврат ТРег(СокрП(РезультатФИО));
КонецФункции
Почему это решение эффективно?
СтрРазделить игнорирует цифры, так как их нет в строке Разделители. Они просто остаются внутри частей слов.СтрРазделить "съедает" сам символ-разделитель, мы заранее подставляем после каждой заглавной буквы её строчную копию, чтобы после разделения слово сохранило свою структуру.ТРег() приводит строку к каноническому виду (например, если на входе было "ИВанов", на выходе получится "Иванов").Хотя в обсуждении на форуме этот метод не был подробно расписан, для программиста 1С важно знать о существовании объекта VBScript.RegExp. Это наиболее профессиональный способ разделения строк CamelCase.
Посмотрим на пример кода, который делает ту же работу одной строкой поиска:
РегВыражение = Новый COMОбъект("VBScript.RegExp");
РегВыражение.Global = Истина;
РегВыражение.Pattern = "([а-яё])([А-ЯЁ])"; // Ищем стык строчной и заглавной буквы
Стр = "КонстантинПетрович";
Результат = РегВыражение.Replace(Стр, "$1 $2"); // Вставляем пробел между ними
Этот метод считается самым быстрым и устойчивым к ошибкам. Он находит место, где маленькая буква граничит с большой, и вставляет туда пробел, не трогая цифры, начало строки или аббревиатуры. Для упрощения работы с регулярными выражениями на платформе 1С подойдёт подсистема для работы с регулярными выражениями.
Подводя итог нашему анализу, дадим несколько советов по выбору метода в зависимости от ситуации:
СокрЛП() и СтрЗаменить(Результат, " ", " "), чтобы исключить появление двойных пробелов.Выяснив причину возникновения проблемы и проанализировав доступные инструменты 1С, мы можем сделать вывод, что универсального "встроенного" метода для разделения слов по регистру не существует, но предложенные алгоритмы полностью закрывают эту потребность.