
Как преобразовать кириллическую строку из UTF-8 в cp1251

Как преобразовать кириллическую строку из UTF-8 в cp1251
При разработке одной программы мне понадобилось преобразовать строки на русском языке из формата UTF-8 в формат cp1251. Внезапно выяснилось, что никакие средства WinAPI не позволяются выполнить эту операцию "одной строкой". Пришлось рассматривать даже варианты с табличным преобразованием, но потом нашлось более простое решение задачи. Алгоритм преобразования получился необычный, но зато гарантированно рабочий. Может быть это поможет сохранить время и нервы кому-нибудь еще.
Для начала вспомогательная функция, которая проверяет, является ли строка кириллической строкой в формате UTF-8. В ней должны быть только однобайтовые символы из первой половины таблицы ASCII и двухбайтовые символы, соответствующие русским буквам. Нулевой символ - признак окончания строки, длина строки значения не имеет.
Code (Assembler) : Убрать нумерацию
- ;--------------------------------------------------------
- ; Проверка строки на соответствие формату
- ; кириллического UTF-8
- ;--------------------------------------------------------
- ; Символы [0x00-0x7F] или двухсимвольные конструкции
- ; вида 0xD0[0x81|0x90-0xBF] или 0xD1[0x91|0x80-0x8F]
- ;--------------------------------------------------------
- ; На выходе:
- ; EAX = 1 - строка соответствует UTF-8
- ; EAX = 0 - строка не соответствует формату
- ;--------------------------------------------------------
- proc is_utf8 tstr:DWORD
- push esi ebx
- mov esi,[tstr]
- ; По умолчанию строка соответствует формату
- mov ebx,1
- .loc_scan:
- lodsb
- ; Окончание строки?
- or al,al
- jz .loc_ret
- ; Проверка символов [0x00-0x7F]
- cmp al,07Fh
- jbe .loc_scan
- ; Проверка двухсимвольной конструкции
- ; 0xD0[0x81|0x90-0xBF]
- cmp al,0D0h
- jne @f
- lodsb
- cmp al,81h
- je .loc_scan
- cmp al,90h
- jb .loc_fail
- cmp al,0BFh
- ja .loc_fail
- jmp .loc_scan
- @@:
- ; Проверка двухсимвольной конструкции
- ; 0xD1[0x91|0x80-0x8F]
- cmp al,0D1h
- jne .loc_fail
- lodsb
- cmp al,91h
- je .loc_scan
- cmp al,80h
- jb .loc_fail
- cmp al,8Fh
- jbe .loc_scan
- .loc_fail:
- ; Строка не соответствует формату
- xor ebx,ebx
- .loc_ret:
- mov eax,ebx
- pop ebx esi
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; Получить нужную длину строки для конвертирования
- invoke MultiByteToWideChar,CP_UTF8,0,str8,-1,0,0
- or eax,eax
- ; Конвертировать строку невозможно
- jz can_not_convert
- ; Промежуточное конвертирование UTF-8 -> UTF-16
- invoke MultiByteToWideChar,CP_UTF8,0,str8,-1,buff16,eax
- ; Получить нужную длину строки для конвертирования
- invoke WideCharToMultiByte,1251,0,buff16,-1,0,0,0,0
- or eax,eax
- ; Конвертировать строку невозможно
- jz can_not_convert
- ; Финальное конвертирование UTF-16 -> cp1251
- invoke WideCharToMultiByte,1251,0,buff16,-1,str1251,eax,0,0
- successfully_converted:
- ; str1251 = отконвертированная строка
- ...
- can_not_convert:
- ; Конвертировать строку невозможно
- ...
Просмотров: 8825 | Комментариев: 8
Метки: Assembler, полезные функции

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(31.07.2016 в 17:44):
Примеры приведены. Берешь и используешь в своей программе.

Денис
(31.07.2016 в 12:04):
Как это можно использовать для перекодировки?

ManHunter
(03.01.2015 в 10:15):
*facepalm*
Igor K, не пиши больше ничего, не надо
Igor K, не пиши больше ничего, не надо

Igor K
(03.01.2015 в 09:24):
Перевод делается с помощью Notepad++

brute
(31.10.2014 в 07:11):
morgot, я имел в виду команды SSE и другие, которые за один такт работают со строками по 128бит (или более).

morgot
(29.10.2014 в 17:03):
brute, какой это "32 разрядный mov"? На 64 битах этой команды нет, по вашему? Про функцию вообще промолчу, могу сказать только то, что ваш образ мышления уж явно не Ассемблер.
ManHunter, спасибо, пригодится.
ManHunter, спасибо, пригодится.

ManHunter
(28.10.2014 в 10:35):
Все равно в нормальном софте придется делать обратную совместимость как минимум до WinXP

brute
(28.10.2014 в 06:34):
Круто! но я бы искал какую-нибудь сишную библиотеку, чтобы заинклудить нужную функцию. Она наверняка эффективнее, чем "старый" 32 разнрядный "mov". П.С. слышал, что в W7 и W8 появилось много новых api-функций, в том числе есть и новые строковые..

Добавить комментарий
Заполните форму для добавления комментария
