При разработке на платформе 1С:Предприятие мы часто сталкиваемся с необходимостью хранить динамические данные. Самый популярный объект для этого — Структура. Однако у структуры есть одно жесткое техническое ограничение: её ключи должны соответствовать правилам именования идентификаторов (переменных). Это означает, что ключ не может начинаться с цифры, не может содержать пробелы и спецсимволы, кроме знака подчеркивания "_".
Если мы пытаемся создать структуру на основе данных, введенных пользователем (например, названия колонок из Excel, имена свойств товаров или произвольные заголовки), мы неизбежно получим ошибку, если строка содержит недопустимые символы. Давайте разберем подробно, как решить эту задачу, какие существуют алгоритмы преобразования и какие есть архитектурные альтернативы.
Прежде чем писать код, давайте определим, что именно платформа считает допустимым ключом. Ключ структуры должен удовлетворять следующим условиям:
Рассмотрим несколько способов превращения строки "Товар №1 (красный)" в валидный ключ типа "Товар_1_красный" или аналогичный.
Если ваша конфигурация построена на базе БСП, самый правильный путь — не изобретать велосипед, а использовать готовые проверенные функции. В модуле СтроковыеФункцииКлиентСервер (или в старых версиях СтандартныеПодсистемыСервер) есть специализированные методы.
Рассмотрим функцию, которая часто используется для генерации имен колонок таблиц значений или полей на форме:
// Пример вызова функции БСП
НовыйКлюч = СтроковыеФункцииКлиентСервер.ВВидеИдентификатора(ИсходнаяСтрока);
Эта функция автоматически заменяет все недопустимые символы на подчеркивания. Также в некоторых версиях БСП можно встретить функцию ПреобразоватьСтрокуВДопустимоеНаименованиеКолонки. Она работает более агрессивно, иногда заменяя символы на их числовые коды, чтобы обеспечить уникальность и обратимость, но читаемость при этом страдает. Для быстрого изучения и подбора функций библиотеки подойдёт справочник по методам БСП с примерами использования.
Если БСП недоступна или её поведение вас не устраивает, мы можем написать собственную функцию. Алгоритм действий следующий:
_ или удаляем.Давайте реализуем надежный вариант функции, который обсуждался в профессиональном сообществе:
Функция ПреобразоватьВКлючСтруктуры(Знач СтрокаВхода) Экспорт
// 1. Убираем лишние пробелы по краям
Результат = СокрЛП(СтрокаВхода);
// 2. Список допустимых символов (можно использовать диапазоны кодов)
// В данном примере пойдем от обратного: заменим все "плохие" на подчеркивание.
// Проще всего разрешить: а-я, А-Я, a-z, A-Z, 0-9, _
ДопустимыеСимволы = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
ДлинаСтроки = СтрДлина(Результат);
ЧистыйКлюч = "";
Для Сч = 1 По ДлинаСтроки Цикл
ТекСимвол = Сред(Результат, Сч, 1);
// Если символ есть в списке допустимых - оставляем, иначе меняем на "_"
Если СтрНайти(ДопустимыеСимволы, ТекСимвол) > 0 Тогда
ЧистыйКлюч = ЧистыйКлюч + ТекСимвол;
Иначе
// Чтобы не было длинных цепочек "____", можно проверять предыдущий символ
Если Прав(ЧистыйКлюч, 1) <> "_" Тогда
ЧистыйКлюч = ЧистыйКлюч + "_";
КонецЕсли;
КонецЕсли;
КонецЦикла;
// 3. Проверка первого символа (не должен быть цифрой)
ПервыйСимвол = Лев(ЧистыйКлюч, 1);
Если СтрНайти("0123456789", ПервыйСимвол) > 0 Тогда
ЧистыйКлюч = "_" + ЧистыйКлюч;
КонецЕсли;
// 4. Если строка оказалась пустой (были одни спецсимволы)
Если ПустаяСтрока(ЧистыйКлюч) Тогда
ЧистыйКлюч = "Ключ_" + Новый УникальныйИдентификатор();
КонецЕсли;
Возврат ЧистыйКлюч;
КонецФункции
Этот код делает ключ читаемым. Однако обратите внимание: строки "Товар №1" и "Товар #1" превратятся в одинаковый ключ Товар_1. Если вам нужно сохранять их в одной структуре, возникнет коллизия (перезапись данных). В этом случае к ключу следует добавлять хеш или инкремент. Для реализации различных вариантов очистки и разбора текста на чистом 1С можно использовать коллекцию методов для работы со строками на платформе 1С.
Если вы работаете на сервере под Windows, самым быстрым и лаконичным способом будет использование COM-объекта VBScript.RegExp. Это позволит заменить все недопустимые символы одной строкой кода без циклов.
Функция ОчиститьСтрокуRegExp(Знач СтрокаВхода)
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;
// Шаблон: всё, что НЕ (^) является буквой, цифрой или подчеркиванием
RegExp.Pattern = "[^а-яёa-z0-9_]";
// Заменяем найденное на подчеркивание
Результат = RegExp.Replace(СтрокаВхода, "_");
// Дополнительно: убираем дублирующиеся подчеркивания
RegExp.Pattern = "_+";
Результат = RegExp.Replace(Результат, "_");
// Проверка на цифру в начале
Если СтрНайти("0123456789", Лев(Результат, 1)) > 0 Тогда
Результат = "_" + Результат;
КонецЕсли;
Возврат Результат;
КонецФункции
Если читаемость ключа для разработчика не важна, а важна только уникальность и скорость, можно использовать генерацию уникального идентификатора или хеша. Этот метод гарантирует, что ключ всегда будет валидным.
Применим метод, предложенный в обсуждении: берем GUID, убираем дефисы и добавляем префикс буквы (так как GUID может начинаться с цифры).
Функция СгенерироватьКлючИзСтроки(Знач СтрокаВхода)
// Вариант 1: Просто случайный ключ (связь с именем теряется)
// Ключ = "_" + СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");
// Вариант 2: Получение хеша от строки (чтобы одинаковые строки давали одинаковый ключ)
// Для этого потребуется ХешированиеДанных (доступно на платформе 8.3)
Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
Хеш.Добавить(СтрокаВхода);
Ключ = "_" + СтрЗаменить(Строка(Хеш.ХешСумма), " ", "");
Возврат Ключ;
КонецФункции
Такой подход часто используется, когда мы загружаем свойства номенклатуры с произвольными именами и нам нужно быстро создать структуру для программной обработки.
Задумаемся, а действительно ли нам нужна именно Структура? Если ключи генерируются динамически из пользовательского ввода, использование Структуры часто является архитектурной ошибкой. Платформа 1С предоставляет объект Соответствие (Map).
Преимущества Соответствия перед Структурой:
Если ваш код не завязан жестко на сериализацию в JSON определенного формата или передачу параметров в методы, требующие именно Структуру, заменим код следующим образом:
// БЫЛО (Проблемный код)
Данные = Новый Структура;
Попытка
Данные.Вставить(ПользовательскаяСтрока, Значение); // Ошибка, если строка некорректна
Исключение
// Приходится мудрить с именами
КонецПопытки;
// СТАЛО (Правильный код)
Данные = Новый Соответствие;
Данные.Вставить(ПользовательскаяСтрока, Значение); // Работает всегда
// Получение данных
ИскомоеЗначение = Данные.Получить(ПользовательскаяСтрока);
Для решения задачи преобразования строки в ключ структуры выбирайте метод исходя из контекста:
СтроковыеФункцииКлиентСервер.ВВидеИдентификатора или самописную очистку символов с заменой на подчеркивания.