При автоматической обработке входящих электронных писем в 1С разработчики часто сталкиваются с ситуацией, когда кириллический текст считывается некорректно. Вместо читаемых слов в строке отображаются хаотичные знаки, а через каждый символ повторяется заглавная русская буква «Р». Проанализируем причину этой проблемы и рассмотрим несколько способов её решения.
Симптом, при котором кириллица превращается в букву «Р» через каждые 1-2 символа, однозначно указывает на расхождение между фактической кодировкой текста и той, в которой платформа 1С пытается его прочитать.
В кодировке UTF-8 большинство кириллических символов кодируется 2 байтами. Первый байт для большинства русских букв имеет значение 0xD0. Если почтовый клиент отправителя или внешняя библиотека передает байтовый поток UTF-8, а платформа 1С интерпретирует его посимвольно в однобайтовой кодировке Windows-1251 (CP1251), происходит следующее:
0xD0 в кодовой таблице CP1251 соответствует заглавной русской букве «Р».В результате весь русский текст превращается в последовательность вида «Рполся». Внутренний тип строки 1С (Unicode UTF-16) фиксирует эти испорченные символы в памяти, поэтому стандартный повторный вызов методов чтения файла без специального преобразования не дает результата.
Разберем наиболее эффективный и современный способ исправления уже прочитанной в память строки. Для этого обратим ошибочно вычитанные символы назад в исходный байтовый поток CP1251, а затем перекодируем его в правильный формат UTF-8.
Рассмотрим пример кода:
// ИсходнаяТекст - строка с искаженными символами (буквами "Р")
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(ИсходнаяСтрока, "windows-1251");
ПравильныйТекст = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, "utf-8");
Этот метод работает быстро, выполняется полностью в оперативной памяти и не требует создания сторонних временных файлов на диске.
Если требуется выполнить конвертацию в памяти, но штатные методы работы с двоичными данными недоступны, можно использовать функции работы с URL-строками. Процесс состоит из двух шагов: сначала строка кодируется в percent-encoding для UTF-8, а затем декодируется с использованием таблицы CP1251.
Посмотрим на пример реализации:
ПромежуточнаяСтрока = КодироватьСтроку(ИсходныйТекст, СпособКодированияСтроки.URLВКодировкеURL, "utf-8");
ИсправленныйТекст = РаскодироватьСтроку(ПромежуточнаяСтрока, СпособКодированияСтроки.URLВКодировкеURL, "windows-1251");
Рассмотрим алгоритм ручного посимвольного разбора строки, если перекодировка выполняется на уровне анализа кодов отдельных символов. В UTF-8 кириллический блок «А–Я» и «а–п» начинается с байта 208 (0xD0), а блок «р–я» — с байта 209 (0xD1).
Проанализируем программный код посимвольной декодировки:
Итог = "";
Длина = СтрДлина(Стр);
Для Н = 1 По Длина Цикл
Знак = Сред(Стр, Н, 1);
Код = КодСимвола(Знак, 1);
Если Код < 128 Тогда
// Символы ASCII оставляем без изменений
Итог = Итог + Знак;
ИначеЕсли Код = 208 Тогда
// Первый байт 208 (0xD0)
Н = Н + 1;
Знак2 = Сред(Стр, Н, 1);
Код2 = КодСимвола(Знак2, 1);
Если Код2 = 129 Тогда
Итог = Итог + "Ё";
Иначе
Итог = Итог + Символ(КодСимвола("А", 1) + Код2 - 144);
КонецЕсли;
ИначеЕсли Код = 209 Тогда
// Первый байт 209 (0xD1)
Н = Н + 1;
Знак2 = Сред(Стр, Н, 1);
Код2 = КодСимвола(Знак2, 1);
Если Код2 = 145 Тогда
Итог = Итог + "ё";
Иначе
Итог = Итог + Символ(КодСимвола("р", 1) + Код2 - 128);
КонецЕсли;
КонецЕсли;
КонецЦикла;
ТекстовыйДокумент и временного файлаКлассический подход включает сохранение полученного текста во временный файл на диске в кодировке CP1251 с последующим считыванием в кодировке UTF-8.
Разберем по шагам работу с файловым объектом:
ИмяФайла = ПолучитьИмяВременногоФайла("txt");
// Записываем искаженную строку как CP1251
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.УстановитьТекст(ИсходныйТекст);
ТекстДок.Записать(ИмяФайла, "windows-1251");
// Считываем файл с явным указанием UTF-8
ТекстДокПеречитанный = Новый ТекстовыйДокумент;
ТекстДокПеречитанный.Прочитать(ИмяФайла, "utf-8");
Результат = ТекстДокПеречитанный.ПолучитьТекст();
// Удаляем временный файл
УдалитьФайлы(ИмяФайла);
ИнтернетПочта и ИнтернетПочтовоеСообщение. Он автоматически обрабатывает MIME-структуру сообщений, учитывая индивидуальную кодировку каждой текстовой части письма.Content-Type в заголовке конкретного элемента Тексты письма, так как кодировка всего письма может отличаться от кодировки его отдельных частей.