Синоним из идентификатора 1С нужен, когда у поля есть имя, а человеческого заголовка нет: колонки произвольного запроса, ключи структуры, реквизиты формы, созданные кодом. Конфигуратор умеет делать это сам: вводите имя нового реквизита «НомерВходящегоДокумента», и поле «Синоним» заполняется строкой «Номер входящего документа». Из кода такого вызова нет, поэтому ниже своя функция. Она разбивает имя по заглавным буквам, не ломает аббревиатуры вроде ИНН и НДС, понимает цифры и подчёркивания и работает и на клиенте, и на сервере.
Выгрузить() у колонок только имена: «КоличествоОстаток», «СуммаОборот». В табличном документе или на форме пользователь видит именно их.Новый РеквизитФормы(Имя, Тип, Путь, Заголовок) заголовок передаётся четвёртым параметром. Если его не заполнить, в шапке колонки окажется имя.Колонки.Добавить() отвечает за заголовок, и писать его руками для двадцати колонок скучно.Самый очевидный вариант, «пробел перед каждой заглавной», ломается на первой же аббревиатуре: «ИННКонтрагента» превращается в «И Н Н Контрагента». Поэтому правил несколько:
Параметр ОтделятьЦифры включает отдельный режим, в котором любая граница «цифра — не цифра» становится пробелом. Он удобен для имён вроде «Ставка20Процентов», но «1С» в этом режиме тоже разорвётся.
| Идентификатор | Результат | Что сработало |
|---|---|---|
| НомерВходящегоДокумента | Номер входящего документа | правила 1 и 5 |
| ИННКонтрагента | ИНН контрагента | правило 2, аббревиатура сохранена |
| НомерСФПоставщика | Номер СФ поставщика | правила 1 и 2 |
| ДатаНачалаИОкончания | Дата начала и окончания | однобуквенное «И» стало строчным |
| Адрес2Строка | Адрес2 строка | правило 3, число слева |
| ВерсияКонфигурации1С | Версия конфигурации 1С | правило 3, число перед аббревиатурой |
| КодGTIN | Код GTIN | латиница обрабатывается так же |
| Сумма_без_скидки | Сумма без скидки | правило 4 |
| Ставка20Процентов + ОтделятьЦифры | Ставка 20 процентов | режим отдельных цифр |
Удобнее всего положить функцию в общий модуль, например СинонимыКлиентСервер, с флажками «Клиент (управляемое приложение)», «Сервер» и «Внешнее соединение». Для обычного приложения добавьте флажок «Клиент (обычное приложение)». Директивы компиляции в общем модуле не пишутся, контекст задают флажки. Если нужна функция только в одной форме, скопируйте её в модуль формы и поставьте перед каждой функцией &НаКлиентеНаСервереБезКонтекста. Нужна платформа 8.3.6 или новее: СтрНайти и СтрСоединить появились в ней.
// Общий модуль СинонимыКлиентСервер
// Флажки: Клиент (управляемое приложение), Сервер, Внешнее соединение.
// Платформа 8.3.6 и выше (СтрНайти, СтрСоединить).
// Делает из идентификатора строку для заголовка:
// "НомерВходящегоДокумента" -> "Номер входящего документа"
// "ИННКонтрагента" -> "ИНН контрагента"
// "ВерсияКонфигурации1С" -> "Версия конфигурации 1С"
//
// Параметры:
// Идентификатор - Строка - имя реквизита, колонки, ключ структуры.
// ОтделятьЦифры - Булево - Истина: "Ставка20Процентов" -> "Ставка 20 процентов".
//
// Возвращаемое значение:
// Строка
//
Функция СинонимИзИдентификатора(Знач Идентификатор, ОтделятьЦифры = Ложь) Экспорт
Идентификатор = СокрЛП(Идентификатор);
Слова = Новый Массив;
Слово = "";
Для Позиция = 1 По СтрДлина(Идентификатор) Цикл
Текущий = Сред(Идентификатор, Позиция, 1);
// Подчёркивание и пробел - явные разделители слов
Если Текущий = "_" Или Текущий = " " Тогда
ДобавитьСлово(Слова, Слово);
Слово = "";
Продолжить;
КонецЕсли;
Если НачалоНовогоСлова(Идентификатор, Позиция, ОтделятьЦифры) Тогда
ДобавитьСлово(Слова, Слово);
Слово = "";
КонецЕсли;
Слово = Слово + Текущий;
КонецЦикла;
ДобавитьСлово(Слова, Слово);
Для Индекс = 0 По Слова.ВГраница() Цикл
ЭтоПервоеСлово = (Индекс = 0);
Слова[Индекс] = РегистрСлова(Слова[Индекс], ЭтоПервоеСлово);
КонецЦикла;
Возврат СтрСоединить(Слова, " ");
КонецФункции
// Истина, если символ в позиции Позиция открывает новое слово.
Функция НачалоНовогоСлова(Стр, Позиция, ОтделятьЦифры)
Если Позиция = 1 Тогда
Возврат Ложь;
КонецЕсли;
Текущий = Сред(Стр, Позиция, 1);
Предыдущий = Сред(Стр, Позиция - 1, 1);
Следующий = Сред(Стр, Позиция + 1, 1);
// Режим "цифры отдельным словом": любая граница цифра/не цифра
Если ОтделятьЦифры И (ЭтоЦифра(Текущий) <> ЭтоЦифра(Предыдущий)) Тогда
Возврат Истина;
КонецЕсли;
Если ЭтоЦифра(Текущий) Тогда
Если ЭтоЦифра(Предыдущий) Тогда
Возврат Ложь;
КонецЕсли;
// Число клеится к аббревиатуре справа ("Код|1С", "Ставка|20НДС"),
// иначе остаётся с предыдущим словом ("Реквизит1", "ОКВЭД2")
ПозицияПослеЧисла = Позиция;
Пока ЭтоЦифра(Сред(Стр, ПозицияПослеЧисла, 1)) Цикл
ПозицияПослеЧисла = ПозицияПослеЧисла + 1;
КонецЦикла;
Возврат ЭтоЗаглавнаяБуква(Сред(Стр, ПозицияПослеЧисла, 1))
И Не ЭтоСтрочнаяБуква(Сред(Стр, ПозицияПослеЧисла + 1, 1));
КонецЕсли;
Если Не ЭтоЗаглавнаяБуква(Текущий) Тогда
Возврат Ложь;
КонецЕсли;
// "Номер|Входящего"
Если ЭтоСтрочнаяБуква(Предыдущий) Тогда
Возврат Истина;
КонецЕсли;
// Конец аббревиатуры или числа перед обычным словом:
// "ИНН|Контрагента", "Адрес2|Строка"; "СуммаНДС" и "Код1С" не режем
Возврат ЭтоСтрочнаяБуква(Следующий);
КонецФункции
// Первое слово - с заглавной, остальные - строчными, аббревиатуры - как есть.
Функция РегистрСлова(Слово, ЭтоПервоеСлово)
ПерваяБуква = Лев(Слово, 1);
Остаток = Сред(Слово, 2);
// Заглавные внутри слова: ИНН, СФ, ОКВЭД2, 1С, GUID
Если НРег(Остаток) <> Остаток Тогда
Возврат Слово;
КонецЕсли;
Если ЭтоПервоеСлово Тогда
Возврат ВРег(ПерваяБуква) + Остаток;
КонецЕсли;
Возврат НРег(ПерваяБуква) + Остаток;
КонецФункции
Процедура ДобавитьСлово(Слова, Слово)
Если Не ПустаяСтрока(Слово) Тогда
Слова.Добавить(Слово);
КонецЕсли;
КонецПроцедуры
Функция ЭтоЗаглавнаяБуква(Сим)
Возврат ВРег(Сим) = Сим И НРег(Сим) <> Сим;
КонецФункции
Функция ЭтоСтрочнаяБуква(Сим)
Возврат НРег(Сим) = Сим И ВРег(Сим) <> Сим;
КонецФункции
Функция ЭтоЦифра(Сим)
Возврат СтрДлина(Сим) = 1 И СтрНайти("0123456789", Сим) > 0;
КонецФункции
Проверка ВРег(Сим) = Сим И НРег(Сим) <> Сим работает потому, что сравнение строк через «=» во встроенном языке учитывает регистр. Вторая половина условия отсекает цифры, подчёркивание и знаки препинания: у них верхний и нижний регистр совпадают. Приём одинаково работает для кириллицы с буквой Ё и для латиницы, чего не скажешь о проверке по кодам символов.
Функция НачалоНовогоСлова смотрит на три символа: предыдущий, текущий и следующий. Заглавная после строчной всегда открывает слово. Заглавная после заглавной или цифры открывает слово, только если за ней идёт строчная: в «ИННКонтрагента» так срабатывает буква «К», а в «СуммаНДС» ни одна буква внутри «НДС» границей не становится.
На первой цифре числа функция пробегает циклом Пока до конца числа и смотрит, что стоит за ним. Если там аббревиатура, то есть заглавная, за которой нет строчной, число отрывается от слова слева и уходит к аббревиатуре: «Код1С» даёт «Код 1С». Иначе число остаётся слева: «Реквизит1», «ОКВЭД2». Выход за конец строки безопасен, потому что Сред() за пределами строки возвращает пустую строку, а она не цифра и не буква.
РегистрСлова проверяет, есть ли заглавные после первой буквы. Если есть, это аббревиатура или «1С», и слово остаётся как есть. Если нет, у слова меняется только первая буква. Поэтому однобуквенные предлоги «И», «В», «С» внутри имени становятся строчными. Встроенная ТРег() здесь не подходит: она переводит в нижний регистр всё, кроме первой буквы каждого слова, и превращает «ИНН» в «Инн».
Если будете менять правила под свою конфигурацию, держите рядом процедуру-проверку и запускайте её после каждой правки. Примеры лежат в соответствии «идентификатор — ожидаемый результат», процедура выводит только расхождения.
// В том же общем модуле СинонимыКлиентСервер
Процедура ПроверитьСинонимИзИдентификатора() Экспорт
Примеры = Новый Соответствие;
Примеры.Вставить("НомерВходящегоДокумента", "Номер входящего документа");
Примеры.Вставить("ИННКонтрагента", "ИНН контрагента");
Примеры.Вставить("НомерСФПоставщика", "Номер СФ поставщика");
Примеры.Вставить("ДатаНачалаИОкончания", "Дата начала и окончания");
Примеры.Вставить("Адрес2Строка", "Адрес2 строка");
Примеры.Вставить("ВерсияКонфигурации1С", "Версия конфигурации 1С");
Примеры.Вставить("ОбменС1С", "Обмен с 1С");
Примеры.Вставить("КодGTIN", "Код GTIN");
Примеры.Вставить("Сумма_без_скидки", "Сумма без скидки");
Расхождений = 0;
Для Каждого Пример Из Примеры Цикл
Результат = СинонимИзИдентификатора(Пример.Ключ);
Если Результат <> Пример.Значение Тогда
Расхождений = Расхождений + 1;
Сообщить(СтрШаблон("%1: ожидали ""%2"", получили ""%3""",
Пример.Ключ, Пример.Значение, Результат));
КонецЕсли;
КонецЦикла;
// Режим с отдельными цифрами
Результат = СинонимИзИдентификатора("Ставка20Процентов", Истина);
Если Результат <> "Ставка 20 процентов" Тогда
Расхождений = Расхождений + 1;
Сообщить("Ставка20Процентов: получили """ + Результат + """");
КонецЕсли;
Сообщить(СтрШаблон("Проверено: %1, расхождений: %2", Примеры.Количество() + 1, Расхождений));
КонецПроцедуры
Три типовых сценария. Функции ниже размещайте в серверном модуле, потому что ТаблицаЗначений на клиенте недоступна. Сама СинонимИзИдентификатора работает и там, и там.
// Серверный общий модуль или модуль объекта обработки
// Заголовки колонок для результата произвольного запроса
Функция ТаблицаСЗаголовками(Запрос) Экспорт
Таблица = Запрос.Выполнить().Выгрузить();
Для Каждого Колонка Из Таблица.Колонки Цикл
Если ПустаяСтрока(Колонка.Заголовок) Или Колонка.Заголовок = Колонка.Имя Тогда
Колонка.Заголовок = СинонимыКлиентСервер.СинонимИзИдентификатора(Колонка.Имя);
КонецЕсли;
КонецЦикла;
Возврат Таблица;
КонецФункции
// Представление реквизита: синоним из конфигурации,
// а если его забыли заполнить - сгенерированный из имени.
// Пример: ПредставлениеРеквизита(Метаданные.Справочники.Номенклатура, "Артикул")
Функция ПредставлениеРеквизита(ОбъектМетаданных, ИмяРеквизита) Экспорт
Реквизит = ОбъектМетаданных.Реквизиты.Найти(ИмяРеквизита);
Если Реквизит <> Неопределено И ЗначениеЗаполнено(Реквизит.Синоним) Тогда
Возврат Реквизит.Синоним;
КонецЕсли;
Возврат СинонимыКлиентСервер.СинонимИзИдентификатора(ИмяРеквизита);
КонецФункции
// Колонки таблицы значений, собранной в коде
Функция НоваяТаблицаОстатков() Экспорт
ТипЧисло = Новый ОписаниеТипов("Число");
Таблица = Новый ТаблицаЗначений;
Для Каждого ИмяКолонки Из СтрРазделить("КоличествоОстаток,СуммаОстаток,СуммаНДС", ",") Цикл
Таблица.Колонки.Добавить(ИмяКолонки, ТипЧисло,
СинонимыКлиентСервер.СинонимИзИдентификатора(ИмяКолонки));
КонецЦикла;
Возврат Таблица;
КонецФункции
ТаблицаСЗаголовками заполняет заголовок там, где он пустой или совпадает с именем колонки. Заголовки, которые вы задали другим способом, не перезаписываются. Подробнее о колонках и их свойствах написано в статье про таблицу значений.
ПредставлениеРеквизита сначала берёт синоним из конфигурации и только при его отсутствии генерирует текст. Это правильный порядок: синоним, который заполнил разработчик, точнее любой автоматики.
Для реквизитов формы, добавленных через ИзменитьРеквизиты(), передайте результат функции четвёртым параметром конструктора РеквизитФормы или присвойте его свойству Заголовок созданного элемента. С ключами структуры всё так же: обходите её циклом и строите подпись из КлючИЗначение.Ключ.
ВРег/НРег от этого избавлена.&НаКлиенте не компилируется, и платформа сообщает «Переменная не определена (СинонимыКлиентСервер)». Нужны флажки «Клиент» и «Сервер» одновременно.СтрНайти и СтрСоединить недоступны, ошибка «Процедура или функция с указанным именем не определена (СтрНайти)». Замените их на Найти и сборку строки в цикле.Реквизит.Синоним = ... в режиме «Предприятие» падает с ошибкой «Поле объекта недоступно для записи (Синоним)». Метаданные в работающей базе только читаются, синонимы меняются в конфигураторе.Готового метода встроенного языка нет. Конфигуратор заполняет синоним автоматически, только когда вы вводите имя объекта в палитре свойств. В коде нужна своя функция, как в этой статье.
Через метаданные: Метаданные.Справочники.Номенклатура.Реквизиты.Артикул.Синоним. Стандартные реквизиты вроде «Код» и «Наименование» лежат в коллекции СтандартныеРеквизиты. Метод Представление() объекта метаданных возвращает синоним, а при пустом синониме возвращает имя.
Начиная с 8.3.23 во встроенном языке есть функции регулярных выражений, например СтрЗаменитьПоРегулярномуВыражению. Вставить пробелы на границах слов ими можно, но регистр слов всё равно придётся менять отдельно, а правила для аббревиатур и цифр в шаблоне читаются хуже, чем в коде. Кроме того, в тонком и веб-клиенте этих функций нет, а СинонимИзИдентификатора можно вызывать прямо из &НаКлиенте. Посимвольный разбор работает на любой платформе начиная с 8.3.6 и проще в отладке.
Разбейте строку по пробелам через СтрРазделить(Синоним, " ", Ложь), у каждого слова переведите в верхний регистр первую букву (ВРег(Лев(Слово, 1)) + Сред(Слово, 2)), затем соедините через СтрСоединить(Слова, ""). Остальные символы, кроме букв, цифр и подчёркивания, уберите. Помните, что идентификатор не может начинаться с цифры.
Да. ВРег и НРег одинаково обрабатывают латиницу, поэтому «CustomerID» превращается в «Customer ID», а «КодGTIN» в «Код GTIN».
Если синонимы нужны не в одной функции, а в универсальной обработке, отчёте по произвольному запросу или выгрузке с десятками полей, быстрее отдать задачу программисту. Опишите, что должно получиться, на странице доработки отчётов и обработок 1С или сразу разместите задачу бесплатно. Оценка на площадке бесплатная, ответ приходит в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.