Разработчики при проектировании современных интерфейсов в 1С часто сталкиваются с интересной особенностью: одни спецсимволы Юникода (например, простой замок ⛫) без проблем вставляются в код, отображаются на формах и выводятся в сообщениях, а другие (например, цветной эмодзи-замок 🔒) наотрез отказываются работать в редакторе кода или полях ввода, хотя отлично отображаются в табличных документах. В этой статье мы подробно разберем, как платформа «1С:Предприятие» работает с Юникодом, почему возникает такая разница в поведении элементов интерфейса и как обойти эти ограничения программным путем.
Для того чтобы понять природу этой проблемы, проанализируем, как устроена работа со строками на уровне платформы. Исторически «1С:Предприятие» использует двухбайтовую кодировку для представления символов. Согласно официальной технической документации для разработчиков внешних компонент, платформа работает со строками в формате Unicode (WCHAR_T) с фиксированным размером символа 2 байта (16 бит).
Такой подход накладывает фундаментальные ограничения на диапазон доступных символов:
U+0000 до U+FFFF (в десятичной системе — до 65 535). Они занимают ровно 2 байта. В этот диапазон попадают практически все используемые языки мира (кириллица, латиница, иероглифы), а также простые графические символы, такие как замок ⛫ (код U+26EB, десятичное значение 9963). Так как этот символ укладывается в 2 байта, он без проблем поддерживается платформой во всех местах.U+FFFF (от 65 536 до 1 114 111) требуют для своего представления уже 4 байта. Сюда относится большинство современных эмодзи, включая цветной замок 🔒 (код U+1F512, десятичное значение 128 274). В кодировке UTF-16 такие символы записываются с помощью так называемых суррогатных пар — комбинации из двух двухбайтовых кодов (высокого и низкого суррогата).Рассмотрим стандартную попытку разработчика получить символ по его десятичному коду. Если мы попытаемся выполнить следующий код для символа с кодом больше 65 535, платформа вернет пустую строку или вызовет ошибку:
// Попытка получить эмодзи напрямую не увенчается успехом
СимволЗамка = Символ(128274); // Возвратит пустую строку
Выясним причину такого поведения. Функция Символ() во встроенном языке 1С жестко ориентирована на работу с двухбайтовыми кодовыми единицами (значения от 0 до 65 535). Она просто не умеет автоматически конвертировать сквозной 32-битный код Юникода (Code Point) в суррогатную пару UTF-16.
Чтобы программно сгенерировать такой символ, нам нужно самостоятельно рассчитать суррогатную пару и сложить два двухбайтовых символа. Напишем универсальную функцию, которая решает эту задачу математически:
Функция ПолучитьСимволЮникода(Знач КодСимвола) Экспорт
// Если символ укладывается в базовую плоскость (2 байта)
Если КодСимвола <= 65535 Тогда
Возврат Символ(КодСимвола);
КонецЕсли;
// Вычисляем суррогатную пару для UTF-16
ВременныйКод = КодСимвола - 65536;
СтаршийСуррогат = Цел(ВременныйКод / 1024) + 55296; // Диапазон 0xD800 - 0xDBFF (55357 для нашего примера)
МладшийСуррогат = (ВременныйКод % 1024) + 56320; // Диапазон 0xDC00 - 0xDFFF (56594 для нашего примера)
Возврат Символ(СтаршийСуррогат) + Символ(МладшийСуррогат);
КонецФункции
Теперь, вызвав эту функцию с кодом 128 274, мы получим корректную строку, состоящую из двух суррогатных символов:
ЭмодзиЗамок = ПолучитьСимволЮникода(128274); // Возвратит строку из двух байтовых единиц, визуально отображаемую как "🔒"
Теперь разберем, почему при попытке интерактивно вставить символ 🔒 в код модуля (Конфигуратор) или в поле ввода на управляемой форме ничего не происходит (символ просто игнорируется или вырезается).
Начиная с версии платформы 8.2.9, разработчики 1С ввели жесткое правило валидации данных. В полях ввода и встроенном текстовом редакторе платформы запрещено использовать символы, недопустимые с точки зрения спецификации XML 1.0. При попытке интерактивного ввода или вставки из буфера обмена такие символы автоматически отсекаются.
Это сделано для обеспечения стабильности сериализации данных. Поскольку конфигурация 1С, выгрузка метаданных, а также многие механизмы обмена (включая веб-сервисы) используют XML, внедрение «нелегальных» с точки зрения старого стандарта XML 1.0 символов могло приводить к фатальным ошибкам при чтении и записи файлов данных.
Интересной особенностью является то, что в макет или интерактивно открытый ТабличныйДокумент символ 🔒 вставить все-таки можно. Посмотрим, почему так происходит.
Табличный документ в 1С использует принципиально отличный от стандартных текстовых полей внутренний движок отображения. Он изначально разрабатывался с упором на максимальную совместимость с форматами электронных таблиц (такими как Microsoft Excel). Движок рендеринга табличного документа напрямую передает строку операционной системе для отрисовки графических глифов (используя шрифты системы, например, Segoe UI Emoji на Windows), минуя строгие фильтры XML-валидации полей ввода.
Если мы запишем программно сформированный символ в ячейку табличного документа, платформа отобразит его корректно:
ТабДок = Новый ТабличныйДокумент;
Область = ТабДок.Область("R1C1");
Область.Текст = ПолучитьСимволЮникода(128274); // Выведет замок в ячейку А1
ТабДок.Показать();
При использовании 4-байтовых символов в коде 1С крайне важно помнить, как встроенный язык обрабатывает длину строк и поиск подстрок. Посмотрим на поведение стандартных функций на примере строки с эмодзи:
СтрокаСЭмодзи = "Замок " + ПолучитьСимволЮникода(128274); // "Замок 🔒"
// Измерим длину строки
ДлинаСтроки = СтрДлина(СтрокаСЭмодзи);
Функция СтрДлина() вернет значение 8, хотя визуально в строке всего 7 символов (6 букв и пробел + 1 эмодзи). Это происходит потому, что функция считает количество двухбайтовых кодовых единиц (char), а не реальных визуальных символов.
Аналогично ведут себя функции работы с подстроками:
// Попытка получить только эмодзи с конца строки
ТолькоЭмодзи = Прав(СтрокаСЭмодзи, 1);
В переменной ТолькоЭмодзи окажется «битый» символ — только младшая половина суррогатной пары (низкий суррогат), который отобразится как пустой квадрат или знак вопроса. Чтобы получить символ корректно, нам нужно брать 2 символа с конца:
// Правильное извлечение 4-байтового символа
ТолькоЭмодзиПравильно = Прав(СтрокаСЭмодзи, 2); // Возвратит полноценный "🔒"
Учитывайте эти особенности при парсинге текстов, которые могут содержать современные символы Юникода, чтобы избежать повреждения данных при обрезке строк.