Разработка и Конфигурация · 11 мин
Как в 1С получить значение перечисления по синониму
Как в 1С найти значение перечисления по его синониму: обход метаданных, готовая функция с примером кода, проверка результата и типичные ошибки разработчика.
Встроенный язык 1С не содержит готового метода «получить значение перечисления по синониму» — в отличие от поиска по имени, который выполняется через индекс метаданных. Поэтому задача решается перебором значений перечисления через объект метаданных и сравнением синонима каждого значения с искомой строкой.
Такая потребность возникает регулярно: при загрузке данных из Excel, CSV или внешних систем значения приходят в «человеческом» виде — «Наличный расчет», «Оплачен», «В работе». Это чаще всего именно синонимы (представления), а не имена значений перечисления в конфигураторе. Программно сопоставить их можно только через метаданные.
Ниже разобраны рабочий алгоритм, готовая универсальная функция, варианты для клиент-серверного и файлового режима, проверка результата и ошибки, из-за которых поиск возвращает пустую ссылку или непредсказуемое значение.
Как устроены имя, синоним и представление перечисления
У каждого значения перечисления есть три разных свойства, которые часто путают. Имя — идентификатор в конфигураторе, например «НаличныйРасчет». По нему работает обращение Перечисления.ФормыОплаты.НаличныйРасчет и функция XMLЗначение. Синоним — строка, которую видит пользователь: «Наличный расчет». Представление — то, что реально выводится в интерфейсе; оно может отличаться от синонима, если задано представление в форме или переопределено локализацией.
Поиск по имени выполняется напрямую: Перечисления.ФормыОплаты[ИмяЗначения]. Поиск по синониму такой возможности не имеет, потому что синоним — это свойство метаданных, а не индексированный ключ. Отсюда и необходимость перебора.
Базовый алгоритм поиска через метаданные
Логика проста: получаем объект метаданных перечисления, перебираем коллекцию ЗначенияПеречисления, для каждого элемента сравниваем свойство Синоним с искомой строкой. При совпадении обращаемся к менеджеру перечисления по имени найденного значения и возвращаем ссылку.
Функция НайтиЗначениеПеречисленияПоСинониму(ИмяПеречисления, ИскомыйСиноним)
МетаданныеПеречисления = Метаданные.Перечисления.Найти(ИмяПеречисления);
Если МетаданныеПеречисления = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Для Каждого Значение Из МетаданныеПеречисления.ЗначенияПеречисления Цикл
Если Значение.Синоним = ИскомыйСиноним Тогда
Возврат Перечисления[ИмяПеречисления][Значение.Имя];
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Функция возвращает Неопределено, если перечисление не существует или синоним не найден. Это важно: вызывающий код должен проверять результат, а не сразу записывать его в реквизит объекта — иначе в базу попадёт пустое значение.
Сравнение в примере регистрозависимое и чувствительно к пробелам. Если данные приходят из внешних источников, стоит нормализовать строки перед сравнением — об этом ниже.
- 1Найдите объект метаданных перечисления через Метаданные.Перечисления.Найти()
- 2Переберите коллекцию ЗначенияПеречисления
- 3Сравните свойство Синоним каждого значения с искомой строкой
- 4При совпадении верните Перечисления[Имя][Значение.Имя]
- 5Проверьте результат на Неопределено перед использованием
Устойчивое сравнение: регистр, пробелы и неразрывные символы
Данные из Excel и CSV часто содержат лишние пробелы, неразрывные пробелы (символ 160) и разный регистр букв. Строгое сравнение = в этом случае даёт ложные промахи: синоним в конфигурации «Наличный расчет», а в файле «наличный расчет» с двойным пробелом.
Практичное решение — нормализовать обе строки перед сравнением: убрать неразрывные пробелы, сократить крайние пробелы и привести к одному регистру. Для этого удобно завести вспомогательную функцию:
Функция НормализоватьСтроку(Строка)
Результат = СтрЗаменить(Строка, Символ(160), " ");
Результат = СокрЛП(Результат);
Возврат НРег(Результат);
КонецФункции
// В цикле поиска:
Если НормализоватьСтроку(Значение.Синоним) = НормализоватьСтроку(ИскомыйСиноним) Тогда
Возврат Перечисления[ИмяПеречисления][Значение.Имя];
КонецЕсли;
Учтите: мягкое сравнение повышает риск неоднозначности. Если два синонима отличаются только регистром или пробелами, будет найдено первое по порядку значение. В типовых конфигурациях такое встречается редко, но при доработках конфигуратора проверить дубли синонимов стоит.
Где размещать функцию и как вызывать с клиента
Обращение к объекту Метаданные доступно на тонком и веб-клиенте, поэтому функцию можно разместить в общем модуле с признаками «Сервер» и «Клиент (обычное приложение)» или «Клиент (управляемое приложение)» — если нужен вызов из клиентского кода без серверного обращения. В типовых решениях для таких задач обычно заводят общий модуль вида «РаботаСПеречислениями».
Если поиск выполняется массово — например, при загрузке тысяч строк из файла — перебирать метаданные для каждой строки расточительно. Эффективнее один раз построить соответствие «синоним → значение» и дальше искать по нему:
Функция СоответствиеСинонимовПеречисления(ИмяПеречисления)
Соответствие = Новый Соответствие;
Для Каждого Значение Из Метаданные.Перечисления[ИмяПеречисления].ЗначенияПеречисления Цикл
Соответствие.Вставить(НРег(СокрЛП(Значение.Синоним)),
Перечисления[ИмяПеречисления][Значение.Имя]);
КонецЦикла;
Возврат Соответствие;
КонецФункции
// Использование при загрузке:
Кэш = СоответствиеСинонимовПеречисления("ФормыОплаты");
Найденное = Кэш.Получить(НРег(СокрЛП(СтрокаИзФайла)));
Такой подход сокращает число обращений к метаданным с одного на строку до одного на всю загрузку и заметно ускоряет обработку больших файлов.
Альтернативные способы поиска значения
Поиск по синониму — не единственный вариант сопоставления. В зависимости от источника данных могут быть удобнее другие подходы.
Сравнение вариантов
Подходит, когда из внешней системы приходит пользовательское представление. Ограничение: синонимы могут меняться при доработке конфигурации, и сопоставление сломается.
Самый надёжный вариант, если внешняя система может передавать имя (НаличныйРасчет). Работает через Перечисления[Имя][ИмяЗначения], не требует перебора.
Оптимально для интеграций, где внешние коды не совпадают ни с именами, ни с синонимами. Требует ведения настроек, но устойчива к переименованиям.
Не применимо: у перечислений нет предопределённых элементов в том смысле, в каком они есть у справочников и планов счетов.
Для долгоживущих интеграций надёжнее всего сопоставление по имени значения или по отдельному регистру соответствий. Синоним — это «презентационный» атрибут: его могут поправить ради красоты интерфейса, и загрузка молча перестанет находить значения.
Проверка результата и типичные ошибки
После вызова функции убедитесь, что возвращено именно значение перечисления, а не Неопределено. Дополнительно можно проверить тип через ТипЗнч или просто вывести найденное значение в сообщение при отладке — представление значения перечисления должно совпасть с исходным синонимом.
Как проверить результат
Ссылка на значение перечисления, представление совпадает с искомым синонимом
Неопределено — синоним не найден или имя перечисления указано неверно
Один и тот же синоним всегда даёт одно значение
Результат зависит от регистра или пробелов во входных данных
Реквизит заполнен найденным значением
Реквизит очищается пустой ссылкой без предупреждения
Ещё одна распространённая ситуация — попытка получить значение перечисления по строке через ЗначениеИзСтрокиВнутр или XMLЗначение. Эти функции работают с внутренним форматом и именами, а не с синонимами, и для пользовательских представлений не подходят.
Ограничения подхода и когда он не подходит
Перебор метаданных — рабочее, но не универсальное решение. Он не подходит, если в конфигурации есть значения с одинаковыми синонимами (будет найдено первое), если синонимы зависят от языка (в многоязычных конфигурациях у синонима может быть несколько вариантов, и свойство Синоним вернёт значение для текущего языка), а также если требуется поиск по частичному совпадению.
Для частичного поиска можно заменить строгое сравнение на СтрНайти(НРег(Значение.Синоним), НРег(ИскомыйФрагмент)) > 0, но тогда нужно обрабатывать ситуацию с несколькими найденными значениями — например, собирать их в массив и возвращать список для выбора пользователем, а не первое попавшееся.
Что важно запомнить
Значение перечисления по синониму находится только перебором метаданных: Метаданные.Перечисления[Имя].ЗначенияПеречисления и сравнение свойства Синоним. Нормализуйте строки перед сравнением, проверяйте результат на Неопределено и кэшируйте соответствие при массовой загрузке.
Частые вопросы
Можно ли найти значение перечисления по синониму без перебора метаданных?
Нет, штатного метода поиска по синониму во встроенном языке нет. Перебор коллекции ЗначенияПеречисления — единственный способ. Если перебор нужен часто, постройте соответствие один раз и ищите по нему.
Что вернёт функция, если синоним не найден?
В приведённой реализации — Неопределено. Это осознанное решение: вызывающий код должен явно обработать ситуацию «не найдено», например записать строку в протокол ошибок загрузки и пропустить её, а не сохранять пустую ссылку в объект.
Работает ли этот код на управляемых формах и тонком клиенте?
Да, объект Метаданные доступен на тонком и веб-клиенте, поэтому функцию можно выполнять и на клиенте. Но при массовой обработке данных лучше выполнять поиск на сервере, чтобы не плодить серверные вызовы.
Как искать, если синонимы заданы на нескольких языках?
Свойство Синоним возвращает значение для текущего языка сеанса. Если нужен конкретный язык, сравнивайте через представление с явным указанием языка или перейдите на сопоставление по имени значения, которое от языка не зависит.
Чем поиск по синониму отличается от поиска по представлению?
Синоним — свойство метаданных, заданное в конфигураторе. Представление — то, что реально выводится пользователю, и оно может быть переопределено. При загрузке из внешних файлов чаще всего сопоставляют именно с синонимом, так как файлы формируются по пользовательским названиям.
Что делать, если внешняя система передаёт коды, не совпадающие ни с именами, ни с синонимами?
Заведите регистр сведений соответствия «внешний код — значение перечисления» и заполняйте его в настройках интеграции. Это устойчивее к переименованиям в конфигурации и позволяет менять сопоставления без доработки кода.