В процессе разработки часто возникает задача преобразования обычного текста в формат Unicode-кодов (например, для формирования JSON, взаимодействия с веб-сервисами или специфическими API). Классический перебор строки в цикле с использованием функции КодСимвола на больших объемах данных работает крайне медленно. Проанализируем более эффективные подходы, которые позволяют решить эту задачу быстро, минимизируя или полностью исключая интерпретируемые циклы 1С.
Один из самых простых и быстрых способов получить экранированные Unicode-последовательности для символов вне диапазона ASCII — это использование объекта ЗаписьJSON. Платформа 1С умеет делать это на уровне собственного оптимизированного кода. Рассмотрим этот метод подробнее:
ЗаписьДЖСОН = Новый ЗаписьJSON;
// Устанавливаем параметры записи, указывая экранирование символов вне ASCII
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(,,, ЭкранированиеСимволовJSON.СимволыВнеASCII);
ЗаписьДЖСОН.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьДЖСОН, "строка");
Результат = ЗаписьДЖСОН.Закрыть();
// Результат будет содержать строку с экранированными символами в кавычках
Этот метод идеально подходит, если ваша задача — перевести кириллицу или спецсимволы в формат \uXXXX. Однако стоит учитывать, что стандартные символы латиницы экранироваться не будут. Если требуется обязательное кодирование всех символов, перейдем к следующим вариантам.
Начиная с версии платформы 8.3.10, у нас появились мощные инструменты для работы с двоичными данными без побайтового перебора. Мы можем получить шестнадцатеричное представление всей строки целиком. Выясним, как это работает:
ДвоичныеДанные, используя кодировку UTF-16LE (Little Endian), так как именно она наиболее близка к внутреннему представлению строк в 1С.ПолучитьГексадецимальнуюСтрокуИзДвоичныхДанных для моментального получения строки вида "41044204...".Пример реализации этой логики:
Функция ПолучитьHexКоды(Текст)
// Получаем двоичные данные в UTF-16LE без BOM
ДД = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF16LE, Ложь);
// Мгновенная конвертация в Hex
Гекс = ПолучитьГексадецимальнуюСтрокуИзДвоичныхДанных(ДД);
Возврат Гекс;
КонецФункции
Важный нюанс: Полученная строка будет содержать коды символов парами байтов. Например, для кириллической "С" (код 0421) в UTF-16LE мы получим "2104". Если нам нужен формат \u0421, нам придется поменять байты местами. Хотя это потребует обработки, она выполняется значительно быстрее, чем работа с каждым символом через Сред и КодСимвола.
Если нам нужно именно посимвольное преобразование, но максимально быстрое, разберем метод с использованием ПотокВПамяти и ЧтениеДанных. Этот способ позволяет читать данные фиксированными порциями по 16 бит (2 байта), что соответствует одному символу Unicode в базовой плоскости.
Функция ПреобразоватьЧерезПоток(Текст)
Поток = Новый ПотокВПамяти;
Запись = Новый ЗаписьДанных(Поток, КодировкаТекста.UTF16, , "");
Запись.ЗаписатьСтроку(Текст);
Запись.Закрыть();
Поток.Перейти(0, ПозицияВПотоке.Начало);
Чтение = Новый ЧтениеДанных(Поток);
МассивКодов = Новый Массив;
// Кэш для ускорения: чтобы не форматировать одинаковые символы многократно
СоответствиеКодов = Новый Соответствие;
Пока Истина Цикл
Код = Чтение.ПрочитатьЦелое16();
Если Код = Неопределено Тогда Прервать; КонецЕсли;
ТекстовыйКод = СоответствиеКодов[Код];
Если ТекстовыйКод = Неопределено Тогда
ТекстовыйКод = "\u" + Формат(Код, "ЧВН=; ЧЦ=4; ЧГ=");
СоответствиеКодов[Код] = ТекстовыйКод;
КонецЕсли;
МассивКодов.Добавить(ТекстовыйКод);
КонецЦикла;
Возврат СтрСоединить(МассивКодов);
КонецФункции
В этом примере мы используем кэширование (переменная СоответствиеКодов). Это критически важный момент для оптимизации: в любом тексте символы повторяются, и нет смысла выполнять операцию Формат() для каждой буквы "а". Мы делаем это один раз, а затем просто берем готовое значение из соответствия.
Проанализируем необычный подход: если набор символов в исходной строке ограничен (например, только алфавит и цифры), можно использовать "массовую замену". Платформенная функция СтрЗаменить написана на языке C++ и работает крайне эффективно с памятью.
Разберем алгоритм:
СтрЗаменить(Текст, Символ, "[" + КодСимвола(Символ) + "]").Несмотря на то, что формально здесь есть цикл по уникальным символам, их количество (обычно не более 100-200) несоизмеримо меньше длины самого текста (который может быть миллионы символов). Это позволяет достичь огромного прироста скорости.
При работе с Unicode важно помнить о суррогатных парах. Некоторые символы (эмодзи, редкие иероглифы) кодируются не двумя байтами, а четырьмя. Если вы используете метод чтения ПрочитатьЦелое16, такой символ "развалится" на два кода. В современных версиях 1С (начиная с 8.3.3) функция КодСимвола умеет корректно возвращать полное значение кода даже для суррогатных пар. Если ваша система должна поддерживать такие символы, лучше использовать методы, опирающиеся на встроенную работу платформы со строками, а не на прямое побайтовое чтение.
Рассмотренные нами методы показывают, что уход от прямой итерации Для Н = 1 По СтрДлина(Текст) в сторону использования ЗаписьJSON, ЧтениеДанных или массовых замен СтрЗаменить позволяет ускорить обработку строк в десятки и сотни раз. Для большинства задач оптимальным будет Способ 3 (Потоки с кэшированием), так как он обеспечивает баланс между универсальностью и скоростью.