В прошлой статье про кодировки я рассматривал вопросы того как можно представить веб-страницу в правильной кодировке. При этом в качестве источника информации о кодовой странице я предлагал использовать либо информацию из заголовков сервера, либо информацию из мета-тегов страницы.
Сегодня рассмотрим ещё один способ получения кодовой страницы для заданной строки с использованием MLang.
Сразу следует отметить, что любой автоматический способ определения кодовой страницы для текста не имеет 100% точности. Думаю, что вы не раз сталкивались с такой ситуацией, когда загружаемая Вами веб-страница в IE имела совершенно нечитабельный текст? Это как раз и следствие того, что браузер ошибся в определении кодировки. Но, как говориться, всегда приходится чем-то жертвовать.
Сегодня воспользуемся интерфейсом MLang под названием IMultiLanguage2. Этот интерфейс содержит все методы, которые имеет его родитель IMultiLanguage, а также ряд новых методов в числе которых необходимый нам DetectInputCodepage — определение кодовой страницы для заданной строки.
Параметры метода DetectInputCodepage следующие:
dwFlag [in] битовый флаг, определяющий специфику входной строки. Допустимые значения флага:
MLDETECTCP_NONE=0;
MLDETECTCP_7BIT=1;
MLDETECTCP_8BIT=2;
MLDETECTCP_DBCS=4;
MLDETECTCP_HTML=8;
dwPrefWinCodePage [in] вспомогательный параметр. Если он равен нулю, то MLang проверяет все возможные кодовые страницы
pSrcStr [in] входная строка для которой определяется кодовая страница.
pcSrcSize [in, out] размер строки. Если функция выполнена успешно, то pcSrcSize содержит количество проанализированный байтов строки.
lpEncoding [in, out] структура DetectEncodingInfo в которой содержится информация по кодовой странице для строки.
pnScores [in, out] Содержит количество элементов массива структур DetectEncodingInfo (для интерфейса IMultiLanguage2 равен 1).
Структура DetectEncodingInfo содержит следующие данные:
tagDetectEncodingInfo = packed record nLangID: SYSUINT; //ID языка nCodePage: SYSUINT;//номер кодовой страницы nDocPercent: SYSINT;//процент текста документа занятого текстом на языке nLangID nConfidence: SYSINT;//относительный параметр, по которому можно судить о точности определения кодовой страницы. Т.к. параметр относительный, то его значение может превысить 100. end;
Соответственно, судя по параметру nConfidence можно делать вывод о том, стоит ли доверять «чутью» MLang или применить другой метод определения кодовой страницы. Давайте проведем небольшой эксперимент: составим небольшую программку, которая будет определять кодировку текста на странице и будем задавать адреса страниц с заведомо известными кодировками и посмотрим сколько раз MLang ошибется.
Итак, открываем Delphi, и создаем приложение примерно следующего вида:
В uses подключаем модуль MLang и, если Вы как и я используете для работы в Сети библиотеку Synapse, то ещё один модуль — httpsend.
Теперь в обработчике onClick кнопки «Detect» пишем:
procedure TForm5.Button1Click(Sender: TObject); var count:integer; i:integer; Data:TStringStream; MultiLang: IMultiLanguage2; DE: tagDetectEncodingInfo; s:PAnsiChar; begin with THTTPSend.Create do begin if HTTPMethod('GET',Edit1.Text) then begin Data:=TStringStream.Create(''); Data.LoadFromStream(Document); end; end; MultiLang:=CoCMultiLanguage.Create as IMultiLanguage2; s:=PAnsiChar(Data.Bytes); i:=Data.Size; FillChar(DE, SizeOf(DE), 0); count:=1; OleCheck(MultiLang.DetectInputCodepage(8,0,s,i,DE,count)); label5.Caption:=IntToStr(DE.nCodePage); label10.Caption:=IntToStr(DE.nConfidence); end;
Обратите внимание на то, каким образом получается значение переменной s:
s:=PAnsiChar(Data.Bytes);
Используются байты строки (нововведение из Delphi 2009). Если написать так:
s:=PAnsiChar(Data.DataString);
то DetectInputCodepage вернет кодовую страницу 1252 для любой страницы.
Теперь начнем проверку. Для начала проверим кодировку страниц моего блога. Результат:
Кодовая страница 65001 — это ни что иное, как utf-8. Теперь проверим главную страницу Гугла:
Тут уже есть неточность. На самом деле www.google.ru имеет кодироку utf-8, но и параметр «уверенности» тоже вернулся менее 100.
Аналогичным образом можно проверить ещё сколь угодно много страниц и получить результат. Могу сказать, что пока писал пост попутно проверил ряд страниц в кодировке koi8-r и результат был верным для всех проверенных страниц.
На сегодня, пожалуй все. Надеюсь, что приведенный выше способ определения кодовой страницы для строки найдет применение в Ваших программах.