Blog. Just Blog

Как узнать кодировку текста

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Для корректного отображения или передачи текстов надо знать, в какой кодировке этот текст записан. Есть инструменты для статистического анализа в виде внешних dll или библиотек на различных языках программирования. А я в этой статье расскажу, как можно решить подобную задачу с использованием системного интерфейса IMultiLanguage2. Насколько мне известно, этот интерфейс создавался для использования в браузере Internet Explorer, в том числе с целью определения кодировок web-страниц.

Как вы могли догадаться, поскольку планируется работа с COM, то первым делом понадобятся GUID'ы и описания интерфейсов.
  1. ; GUID {275C23E2-3747-11D0-9FEA-00AA003F8646}
  2. CLSID_CMultiLanguage \
  3.     dd 0275C23E2h
  4.     dw 03747h
  5.     dw 011D0h
  6.     db 09Fh, 0EAh, 000h, 0AAh, 000h, 03Fh, 086h, 046h
  7.  
  8. ; GUID {DCCFC164-2B38-11D2-B7EC-00C04F8F5D9A}
  9. IID_IMultiLanguage2 \
  10.     dd 0DCCFC164h
  11.     dw 02B38h
  12.     dw 011D2h
  13.     db 0B7h, 0ECh, 000h, 0C0h, 04Fh, 08Fh, 05Dh, 09Ah
  14.  
  15. ; IID_IMultiLanguage2 Interface
  16. struct IMultiLanguage2
  17.     ; IUnknown
  18.     QueryInterface             dd ?   ; 000h
  19.     AddRef                     dd ?   ; 004h
  20.     Release                    dd ?   ; 008h
  21.     ; IMultiLanguage2
  22.     GetNumberOfCodePageInfo    dd ?   ; 00Ch
  23.     GetCodePageInfo            dd ?   ; 010h
  24.     GetFamilyCodePage          dd ?   ; 014h
  25.     EnumCodePages              dd ?   ; 018h
  26.     GetCharsetInfo             dd ?   ; 01Ch
  27.     IsConvertible              dd ?   ; 020h
  28.     ConvertString              dd ?   ; 024h
  29.     ConvertStringToUnicode     dd ?   ; 028h
  30.     ConvertStringFromUnicode   dd ?   ; 02Ch
  31.     ConvertStringReset         dd ?   ; 030h
  32.     GetRfc1766FromLcid         dd ?   ; 034h
  33.     GetLcidFromRfc1766         dd ?   ; 038h
  34.     EnumRfc1766                dd ?   ; 03Ch
  35.     GetRfc1766Info             dd ?   ; 040h
  36.     CreateConvertCharset       dd ?   ; 044h
  37.     ConvertStringInIStream     dd ?   ; 048h
  38.     ConvertStringToUnicodeEx   dd ?   ; 04Ch
  39.     ConvertStringFromUnicodeEx dd ?   ; 050h
  40.     DetectCodepageInIStream    dd ?   ; 054h
  41.     DetectInputCodepage        dd ?   ; 058h
  42.     ValidateCodePage           dd ?   ; 05Ch
  43.     GetCodePageDescription     dd ?   ; 060h
  44.     IsCodePageInstallable      dd ?   ; 064h
  45.     SetMimeDBSource            dd ?   ; 068h
  46.     GetNumberOfScripts         dd ?   ; 06Ch
  47.     EnumScripts                dd ?   ; 070h
  48.     ValidateCodePageEx         dd ?   ; 074h
  49. ends
  50.  
  51. struct DetectEncodingInfo
  52.         nLangID     dd ?
  53.         nCodePage   dd ?
  54.         nDocPercent dd ?
  55.         nConfidence dd ?
  56. ends
  57.  
  58. MLDETECTCP_NONE = 0
Для определения кодировки текста в интерфейсе IMultiLanguage2 предусмотрены два метода: DetectCodepageInIStream и DetectInputCodepage. Первый предназначен для работы с объектами Stream, а второй метод работает со строками в памяти. Вот им и воспользуемся.

В общих чертах код определения кодировки будет выглядеть примерно так. Создаем интерфейс IMultiLanguage2, затем через указанный выше метод получаем данные о кодировке или нескольких кодировках, если требуется именно такой вариант.
  1.         ; Инициализация COM
  2.         invoke  CoInitialize,NULL
  3.  
  4.         ; Создать объект
  5.         invoke  CoCreateInstance,CLSID_CMultiLanguage,NULL,\
  6.                 CLSCTX_INPROC_SERVER,IID_IMultiLanguage2,\
  7.                 pMultiLanguage
  8.  
  9.         ; Первая строка
  10.         mov     [scores],1
  11.  
  12.         ; Длина строки
  13.         invoke  lstrlen,string1
  14.         mov     [str_len],eax
  15.  
  16.         mov     eax, [pMultiLanguage]
  17.         mov     eax, [eax]
  18.         stdcall dword [eax+IMultiLanguage2.DetectInputCodepage],\
  19.                 [pMultiLanguage],\
  20.                 MLDETECTCP_NONE,0,\
  21.                 string1,str_len,\
  22.                 deinfo,scores
  23.  
  24.         mov     eax,deinfo
  25.  
  26.         ; [deinfo.nDocPercent] - процент символов в строке с этой кодировкой
  27.         ; [deinfo.nConfidence] - достоверность результата
  28.  
  29.         ; Получить подробную информацию о кодировке
  30.         invoke  GetCPInfoEx,[deinfo.nCodePage],0,cpinfo
  31.  
  32.         ; Прибраться за собой
  33.         mov     eax, [pMultiLanguage]
  34.         mov     eax, [eax]
  35.         stdcall dword [eax+IMultiLanguage2.Release],[pMultiLanguage]
  36.  
  37.         invoke  CoUninitialize
Код несложный, но вот по значениям параметров метода DetectInputCodepage могут потребоваться пояснения. dwFlag - тип символов исходного текста, возможные значения флага и их описания можно посмотреть в MSDN. dwPrefWinCodePage - предпочтительная кодировка, тут лучше передавать дефолтное нулевое значение. pSrcStr - указатель на строку, для которой надо определить кодировку. Важное замечание: длина строки должна быть не менее 255 символов, иначе метод вернет неизвестную ошибку. Если строка короче, то можно просто несколько раз слепить ее с самой собой до достижения нужной длины. pcSrcSize - указатель на переменную, в которую записана длина исходной строки, после вызова метода сюда будет записано количество символов, которое было обработано. lpEncoding - указатель на массив структур DetectEncodingInfo, в которые будут записаны варианты кодировок. Их может быть одна или несколько. pnScores - указатель на переменную с количеством структур в массиве, после вызова метода в эту переменную будет записано фактическое значение количества кодировок, но не более исходного количества.

В полях структур DetectEncodingInfo содержится информация о языке и кодировке, в поле nDocPercent содержится процентное количество символов в исходной строке, которые соответствуют этой кодировке. В поле nConfidence записан коэффициент достоверности, чем это значение больше, тем точнее определена кодировка. Что интересно, это не процентное значение, так как оно запросто может оказаться больше 100.

После получения списка кодировок можно пройтись по массиву, в частности по полям nCodePage, и уточнить человекопонятную информацию по каждой из них. Нечто подобное мы уже делали.

Ну и конечно же надо понимать, что любой автоматический способ определения кодировки текста не дает 100% точности. Однако, описанного в статье способа в подавляющем большинстве случаев будет достаточно.

В приложении пример программы с исходным текстом, которая определяет и выводит на экран кодировки для двух разных строк.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Detect.Encoding.Demo.zip (3,821 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 173 | Комментариев: 0

Метки: Assembler, COM

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0046 сек.) / Память: 4.5 Mb
Наверх