К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как найти значение перечисления по значению в 1С

Как в 1С найти значение перечисления по строке: методы НайтиПоИмени и НайтиПоСинониму, обход метаданных, проверка результата и типичные ошибки разработчиков.

Задача найти значение перечисления по строке возникает в 1С постоянно: при загрузке данных из файлов, обмене с внешними системами, разборе ответов веб-сервисов. Во всех этих случаях на входе есть текст, а нужно получить ссылку вида ПеречислениеСсылка.СтавкиНДС.НДС20. Встроенный язык предоставляет для этого несколько штатных механизмов, и выбор зависит от того, что именно известно: имя значения в конфигураторе, его синоним или представление, которое пришло извне.

Ключевой момент, который нужно понять сразу: перечисление в 1С — это фиксированный список значений, заданный в конфигураторе, а не справочник. У значений перечисления нет кода и наименования в привычном смысле, есть имя (идентификатор в метаданных) и синоним (представление для пользователя). Поэтому «поиск по значению» обычно означает одно из трёх: поиск по имени, поиск по синониму или сопоставление произвольной строки через собственную таблицу соответствий.

Что такое значение перечисления и как оно хранится

Перечисление — объект метаданных, значения которого жёстко заданы разработчиком в конфигураторе. Пользователь не может добавить новое значение в режиме предприятия, в отличие от справочника. Каждое значение имеет имя (латинский идентификатор, например НДС20) и синоним (например, «20 %»), который видит пользователь в интерфейсе.

В базе данных значение перечисления хранится как порядковый номер (индекс) внутри списка значений. Это важно понимать при обменах: номер значения может измениться, если в конфигураторе переставить значения местами, поэтому хранить и передавать перечисления по индексу — плохая практика. Для обмена корректно использовать имя значения.

В коде значение перечисления доступно через менеджер: Перечисления.СтавкиНДС.НДС20. Тип такого значения — ПеречислениеСсылка.СтавкиНДС. Именно ссылку этого типа и нужно получить в результате поиска по строке.

Поиск по имени значения: метод НайтиПоИмени

Самый надёжный способ — когда известно имя значения, как оно задано в конфигураторе. Для этого у менеджера перечисления есть метод НайтиПоИмени(), который принимает строку и возвращает ссылку на значение или Неопределено, если такого имени нет.

СтрокаИмени = "НДС20";

ЗначениеСтавки = Перечисления.СтавкиНДС.НайтиПоИмени(СтрокаИмени);

Если ЗначениеСтавки = Неопределено Тогда

Сообщить("Значение перечисления не найдено: " + СтрокаИмени);

Иначе

// работаем со значением

КонецЕсли;

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

Если имя перечисления тоже известно только как строка (например, при универсальной загрузке), менеджер можно получить через метаданные: Перечисления[ИмяПеречисления].НайтиПоИмени(ИмяЗначения). Перед этим проверьте существование самого перечисления через Метаданные.Перечисления.Найти(ИмяПеречисления), иначе обращение к несуществующему менеджеру вызовет исключение.

Поиск значения по имени
  1. 1
    Получите строку с именем значения и очистите её функцией СокрЛП()
  2. 2
    Вызовите Перечисления.<ИмяПеречисления>.НайтиПоИмени(Строка)
  3. 3
    Проверьте результат на Неопределено
  4. 4
    При отсутствии значения зафиксируйте строку в журнале или сообщите пользователю

Поиск по синониму и представлению

Часто из внешней системы приходит не имя, а пользовательское представление: «20 %», «Без НДС», «Оплачен». В этом случае используется метод НайтиПоСинониму(), который сравнивает строку с синонимами значений, заданными в конфигураторе.

СтрокаИзФайла = "20 %";

ЗначениеСтавки = Перечисления.СтавкиНДС.НайтиПоСинониму(СтрокаИзФайла);

Если ЗначениеСтавки = Неопределено Тогда

// синоним не совпал — пробуем другие варианты

КонецЕсли;

Ограничений у этого подхода два. Во-первых, синонимы могут меняться при доработке конфигурации, и загрузка «отвалится» без изменения кода. Во-вторых, внешняя система может присылать представление, которое не совпадает с синонимом ни по регистру, ни по знакам препинания. Поэтому поиск по синониму подходит только тогда, когда формат входящих данных стабилен и согласован.

Если точного совпадения нет, применяют перебор значений через метаданные со сравнением без учёта регистра:

Функция НайтиЗначениеПоСинониму(ИмяПеречисления, ИскомаяСтрока)

ИскомаяСтрока = НРег(СокрЛП(ИскомаяСтрока));

Для Каждого ЗначениеМетаданных Из Метаданные.Перечисления[ИмяПеречисления].ЗначенияПеречисления Цикл

Если НРег(ЗначениеМетаданных.Синоним) = ИскомаяСтрока Тогда

Возврат Перечисления[ИмяПеречисления][ЗначениеМетаданных.Имя];

КонецЕсли;

КонецЦикла;

Возврат Неопределено;

КонецФункции

Перебор значений через метаданные

Универсальный вариант, когда критерий поиска нестандартный — например, нужно найти значение по части синонима, по имени с нормализацией или по собственному правилу. Коллекция Метаданные.Перечисления[Имя].ЗначенияПеречисления содержит описания всех значений, у каждого доступны свойства Имя и Синоним.

Получив имя из метаданных, ссылку на значение получают обращением по строковому ключу: Перечисления[ИмяПеречисления][ИмяЗначения]. Такой приём работает и когда имя перечисления заранее неизвестно, что удобно для универсальных обработок загрузки.

Учтите, что перебор выполняется на каждый вызов. Если поиск делается в цикле при загрузке тысяч строк файла, разумно один раз построить соответствие «строка → значение» и дальше брать значения из него, а не перебирать метаданные повторно.

Кэшируйте результат поиска в Соответствие: при загрузке больших файлов это убирает повторные обходы метаданных и заметно ускоряет обработку без изменения логики.
ПЗ
Практическое замечание

Сопоставление произвольных строк через таблицу соответствий

Когда внешняя система присылает свои коды, не совпадающие ни с именами, ни с синонимами («VAT20», «std», «0»), прямой поиск не поможет. Правильное решение — явная таблица соответствий: соответствие в коде, регистр сведений или макет, где внешнему значению сопоставлено значение перечисления.

СоответствиеСтавок = Новый Соответствие;

СоответствиеСтавок.Вставить("VAT20", Перечисления.СтавкиНДС.НДС20);

СоответствиеСтавок.Вставить("VAT10", Перечисления.СтавкиНДС.НДС10);

ЗначениеСтавки = СоответствиеСтавок.Получить(КодИзФайла);

Если ЗначениеСтавки = Неопределено Тогда

ВызватьИсключение "Неизвестный код ставки: " + КодИзФайла;

КонецЕсли;

Для долгоживущих интеграций таблицу соответствий лучше выносить в регистр сведений: тогда при появлении новых кодов настройку выполняет пользователь или консультант без изменения кода и обновления конфигурации.

Маршрут решения

Как выбрать способ поиска

Известно имя значения из конфигуратораИспользуйте НайтиПоИмени() — самый быстрый и устойчивый вариант
Известен синоним в стабильном форматеИспользуйте НайтиПоСинониму() с проверкой на Неопределено
Написание строки нестабильноПереберите метаданные с нормализацией НРег() и СокрЛП()
Внешняя система присылает свои кодыПостройте таблицу соответствий в коде или регистре сведений

Проверка результата и обработка ошибок

Главное правило: любой поиск перечисления по строке может вернуть Неопределено. Если проигнорировать проверку и присвоить результат реквизиту объекта, ошибка может проявиться позже — при проведении документа или в отчёте, и искать причину будет сложнее. Проверяйте результат сразу после поиска.

Для контроля корректности загрузки полезно проверять и обратную сторону: что полученное значение действительно принадлежит нужному перечислению. Это делается через ТипЗнч() и сравнение с Тип("ПеречислениеСсылка.ИмяПеречисления").

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

Контрольные точки

Как проверить результат

Возвращаемое значение
Норма

Не равно Неопределено, тип — ПеречислениеСсылка нужного вида

Тревожный признак

Неопределено или значение другого типа

Строка для поиска
Норма

Совпадает с именем или синонимом после СокрЛП()

Тревожный признак

Лишние пробелы, другой регистр, похожие символы кириллицы/латиницы

Протокол загрузки
Норма

Все строки сопоставлены, ошибок нет

Тревожный признак

Есть пропущенные строки без фиксации причины

Типичные ошибки при поиске перечислений

Наиболее частая ошибка — поиск по представлению, полученному через Строка(ЗначениеПеречисления), на другой базе. Представление зависит от синонима и локализации, поэтому при обмене между разными конфигурациями такой подход ненадёжен. Для обмена сериализуйте имя значения, а на приёмной стороне используйте НайтиПоИмени().

Вторая группа ошибок связана с XML-сериализацией: при выгрузке через XMLСтрока() перечисление преобразуется в имя значения, и обратно его получают через XMLЗначение() с указанием типа. Попытка скормить эту строку методу НайтиПоСинониму() закономерно ничего не найдёт.

Типичные ошибки
01
Нет проверки на Неопределено — при несовпадении строки ошибка всплывает далеко от места поиска
02
Поиск по синониму при нестабильном формате входящих данных — загрузка ломается при любом изменении написания
03
Передача перечисления между базами по представлению вместо имени значения
04
Хранение и передача индекса значения — порядок значений в конфигураторе может измениться
05
Обращение Перечисления[Имя] без проверки существования перечисления в метаданных

FAQ: частые вопросы

Чем НайтиПоИмени отличается от НайтиПоСинониму?

НайтиПоИмени ищет по идентификатору значения из конфигуратора (например, «НДС20»), НайтиПоСинониму — по пользовательскому представлению («20 %»). Первый способ устойчив к переименованию синонимов, второй удобен, когда из внешних данных приходит именно видимый текст.

Что возвращает поиск, если значение не найдено?

Оба метода возвращают Неопределено, исключение не возникает. Поэтому результат всегда нужно проверять перед использованием: присвоение Неопределено реквизиту с типом «перечисление» приведёт к записи пустого значения или ошибке в зависимости от контекста.

Как получить имя значения перечисления, имея само значение?

Через метаданные: найдите индекс значения через Перечисления.<Имя>.Индекс(Значение), затем возьмите Метаданные.Перечисления[<Имя>].ЗначенияПеречисления.Получить(Индекс).Имя. Либо используйте XMLСтрока(Значение) — она вернёт имя значения строкой.

Можно ли найти значение перечисления запросом?

Прямого поиска по имени в запросе нет, но в запросе можно сравнивать поле с конкретным значением через ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или параметр. Чтобы подобрать значение по строке, её сначала ищут в коде, а готовую ссылку передают в запрос параметром.

Как организовать поиск, если имена значений в двух базах разные?

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

Почему НайтиПоИмени не находит значение, хотя оно есть в конфигураторе?

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

Итог

Что важно запомнить

Основной инструмент поиска — НайтиПоИмени() для имён и НайтиПоСинониму() для представлений; при нестандартных строках используйте перебор метаданных или таблицу соответствий. Результат всегда проверяйте на Неопределено, а при обмене между базами передавайте имя значения, а не представление или индекс.