В процессе разработки на платформе 1С программисты часто сталкиваются с необходимостью обработки данных, поступающих от внешнего оборудования (весы, сканеры, терминалы) или через низкоуровневые API. Часто такие данные передаются в шестнадцатеричном виде (Hex). Например, последовательность 3D 30 30... должна превратиться в понятный текст =00000.0(kg). В этой статье мы подробно разберем, как реализовать такое преобразование, какие нюансы платформы стоит учитывать и как избежать типичных ошибок при работе с кодировками.
Прежде чем приступать к использованию встроенных функций, проанализируем входные данные. Шестнадцатеричная строка часто содержит пробелы или разделители для удобства чтения человеком (например, "3D 30 30"). Однако системные методы 1С ожидают «чистую» строку, состоящую только из символов 0-9 и A-F.
Рассмотрим процедуру очистки строки. Если мы попытаемся передать строку с пробелами в функцию ПолучитьДвоичныеДанныеИзHexСтроки, платформа вызовет исключение. Поэтому первым делом выполним замену:
ИсходнаяСтрока = "3D 30 30 30 30 30 2E 30 28 6B 67 29 0D 0A";
ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, " ", "");
// Теперь ЧистаяСтрока имеет вид "3D30303030302E30286B67290D0A"
Также важно убедиться, что длина строки четная. Каждый байт информации кодируется ровно двумя символами Hex. Если длина нечетная, это свидетельствует о повреждении данных или ошибке передачи.
Начиная с версии платформы 8.3.10, разработчикам доступны мощные инструменты для работы с бинарными данными. Это самый быстрый и предпочтительный способ. Мы преобразуем Hex-строку в объект ДвоичныеДанные, а затем получим из них текст в нужной кодировке (в нашем примере это ASCII или UTF-8).
Разберем по шагам алгоритм преобразования:
// 1. Очищаем строку
HexСтрока = "3D 30 30 30 30 30 2E 30 28 6B 67 29 0D 0A";
ЧистаяСтрока = СтрЗаменить(HexСтрока, " ", "");
// 2. Преобразуем Hex в ДвоичныеДанные
Попытка
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзHexСтроки(ЧистаяСтрока);
Исключение
Сообщить("Ошибка преобразования: неверный формат Hex-строки");
Возврат;
КонецПопытки;
// 3. Получаем строку в нужной кодировке (например, ASCII)
Результат = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.ANSI);
Сообщить(Результат); // Выведет: =00000.0(kg)
В данном примере мы использовали КодировкаТекста.ANSI, так как ASCII является подмножеством этой кодировки. Если данные содержат кириллицу в формате UTF-8, следует заменить параметр на КодировкаТекста.UTF8.
Иногда требуется более тонкая манипуляция данными, например, если Hex-строка является частью более сложного пакета. В таких случаях удобно использовать БуферДвоичныхДанных. Проанализируем ситуацию, когда нам нужно явно указать кодировку UTF-16 или работать с данными побайтово.
HexСтрока = "3D30303030302E30286B67290D0A";
// Превращаем строку в буфер
Буфер = ПолучитьБуферДвоичныхДанныхИзHexСтроки(HexСтрока);
// Читаем из буфера строку в кодировке UTF-8
ТекстРезультат = ПолучитьСтрокуИзБуфераДвоичныхДанных(Буфер, "UTF-8");
Этот метод аналогичен первому, но использование объекта БуферДвоичныхДанных позволяет выполнять дополнительные операции, такие как конкатенация буферов или чтение отдельных байтов через индексы, что полезно в сложных протоколах обмена.
Если ваша конфигурация работает на платформе ниже 8.3.10, встроенная функция ПолучитьДвоичныеДанныеИзHexСтроки будет недоступна. В этом случае мы можем применить подход с использованием функции ЧислоИзШестнадцатеричнойСтроки (доступна с 8.3.10) или написать собственный парсер. Выясним, как реализовать перебор строки по 2 символа.
Проанализируем пример кода, который эмулирует работу встроенных функций:
Функция HexВСтрокуВручную(Знач HexСтрока)
HexСтрока = СтрЗаменить(HexСтрока, " ", "");
Результат = "";
Для Индекс = 1 По СтрДлина(HexСтрока) / 2 Цикл
// Вырезаем по два символа (один байт)
БайтHex = Сред(HexСтрока, (Индекс - 1) * 2 + 1, 2);
// Преобразуем 16-ричный код в число (код символа)
КодСимвола = ЧислоИзШестнадцатеричнойСтроки("0x" + БайтHex);
// Преобразуем код в символ по таблице ASCII
Результат = Результат + Символ(КодСимвола);
КонецЦикла;
Возврат Результат;
КонецФункции
Важное ограничение: функция Символ() в 1С работает с кодировкой Unicode. Для базовых символов ASCII (коды 0-127) этот метод работает идеально. Однако, если в Hex-строке зашифрованы символы национальной кодировки (например, Windows-1251 с кодами выше 127), этот метод может вернуть неверные символы, так как 1С интерпретирует их как Unicode-коды.
Для максимально надежной работы с различными кодировками на старых платформах (включая 8.2) часто используют COM-объект ADODB.Stream. Он позволяет корректно интерпретировать поток байтов как текст в любой заданной кодировке.
Рассмотрим, как это работает:
Charset (например, "windows-1251").ReadText.Этот метод считается "тяжелым" из-за использования COM, но он является самым гибким для систем, где отсутствуют современные встроенные функции работы с двоичными данными.
Проанализируем основные проблемы, с которыми сталкиваются 1С-разработчики при работе с Hex:
1. Ошибка "Неверный формат строки": Проверьте наличие лишних символов. Используйте регулярные выражения или простую очистку через СтрЗаменить. Помните, что в строке должны быть только 0123456789ABCDEF.
2. Проблема с кодировкой (Кракозябры): Если вместо ожидаемого текста вы видите странные символы, значит, кодировка Hex-данных не совпадает с кодировкой, указанной в функции ПолучитьСтрокуИзДвоичныхДанных. Выясните у поставщика данных, в каком формате они приходят: UTF-8, ANSI или UTF-16.
3. Использование ЧислоИзШестнадцатеричнойСтроки для всей строки: Попытка передать всю длинную Hex-строку в эту функцию — частая ошибка. Эта функция предназначена для преобразования **одного** числа. Для текста ее нужно использовать только внутри цикла, обрабатывая по 2 символа за раз.
Подводя итог, можно сказать, что для современных версий 1С (8.3.10+) задача решается буквально в две строки кода. Для более старых систем требуется написание обертки, имитирующей побайтовое чтение. Выбор метода зависит от требований к производительности и версии используемой платформы.