Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  07:57[Войти] | [Зарегистрироваться]
Ответ на вопрос № 68134

28-01-2009 01:17
Подскажите о преобразовании кодировки в D2009. Беру содержимое HTML-документа (док-т в кодировке 1251) с помощью функции

function TIdHTTP.Get(AURL: string): string;


Результат получается в некоем виде, который нестандартен для D2009 (UTF-16LE, как я понимаю), но работал в D2007. Как перекодировать?

Спасибо, судари.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

28-06-2013 13:07
Я решил эту проблему так


var
  Utf2WinTable : array [0..65, 0..1] of string = (
  (#208#144,#192), (#208#145,#193), (#208#146,#194),
  (#208#147,#195), (#208#148,#196), (#208#149,#197),
  (#208#129,#168), (#208#150,#198), (#208#151,#199),
  (#208#152,#200), (#208#153,#201), (#208#154,#202),
  (#208#155,#203), (#208#156,#204), (#208#157,#205),
  (#208#158,#206), (#208#159,#207), (#208#160,#208),
  (#208#161,#209), (#208#162,#210), (#208#163,#211),
  (#208#164,#212), (#208#165,#213), (#208#166,#214),
  (#208#167,#215), (#208#168,#216), (#208#169,#217),
  (#208#170,#218), (#208#171,#219), (#208#172,#220),
  (#208#173,#221), (#208#174,#222), (#208#175,#223),
  (#208#176,#224), (#208#177,#225), (#208#178,#226),
  (#208#179,#227), (#208#180,#228), (#208#181,#229),
  (#209#145,#184), (#208#182,#230), (#208#183,#231),
  (#208#184,#232), (#208#185,#233), (#208#186,#234),
  (#208#187,#235), (#208#188,#236), (#208#189,#237),
  (#208#190,#238), (#208#191,#239), (#209#128,#240),
  (#209#129,#241), (#209#130,#242), (#209#131,#243),
  (#209#132,#244), (#209#133,#245), (#209#134,#246),
  (#209#135,#247), (#209#136,#248), (#209#137,#249),
  (#209#138,#250), (#209#139,#251), (#209#140,#252),
  (#209#141,#253), (#209#142,#254), (#209#143,#255) );
//////////////////////////////////////////////////////////
function FixString(const AData: String): String;
  var
    S: RawByteString;
    X: Integer;
  begin
    SetLength(S, Length(AData));    // выделили память под ANSI-буфер
    for X := 1 to Length(AData) do  // переносим данные из вида 00A400B700E700D5 в A4B7E7D5
      S[X] := AnsiChar(AData[X]);
    SetCodePage(S, 1251, False);    // пометим, что данные A4B7E7D5имеют кодировку Win1251.
                                    // False указывает на то, что сами данные менять не надо -
                                    // мы просто указываем, в какой они кодировке
    Result := S;                    // здесь компилятор автоматически преобразует строку из ANSI/Win1251 в unicode
end;

function Utf8ToWin(s : string) : string;
var i : integer;
  res  :string;
begin
  res:=s;
  for I := 0 to 65 do
    if pos(Utf2WinTable[i,0],res)>0
      then res := StringReplace(res, Utf2WinTable[i,0], Utf2WinTable[i,1], [rfReplaceAll]);

  Result:=res;
end;

///Пример использования

        str:=FixString(TIdHTTP1.Get(yaLink+AUrl+'+|+host:www.'+AUrl));
        str:=Utf8ToWin(str);


То есть вначале нормализуем текст, потом из utf-8 переводим в windows 1251 и кириллицы правильно отображаются

13-07-2010 10:06
Кстати, чем делать этот метод через одно место с исправлением строки - проще воспользоваться перегруженным вариантом метода Get, который возвращает бинарный поток без преобразования - тогда мы сможем перегнать его в строку (RawByteString), а FixString будет не нужен (останется только вызов SetCodePage на буфер в RawByteString).

Альтернативно, можно воспользоваться тем же, чем пользуется Internet Explorer: MLang-ом. Например.

Это намного проще и универсальнее (окей: проще, когда уже написано кем-то другим), поскольку обрабатывает любую кодировку.

12-01-2010 11:18 | Комментарий к предыдущим ответам
>>> Эта функция у меня выводит мусор
Да, к сожалению, там проблема в первой строке. При таком присвоении некоторые байты могут меняться. Это не то, что надо (надо побайтовое копирование без изменение). Так что только циклом.

>>> Также следующий код работает у меня нормально и без FixString
Я написал, что сейчас происходит в Indy, из-за чего возникает проблема. А в Indy происходит именно передача en8Bit, а не TEncoding.GetEncoding(1251).

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

12-01-2010 09:34 | Комментарий к предыдущим ответам
Эта функция у меня выводит мусор:


function FixString(const AData: String): String;
type
  TW1252 = type AnsiString(1252);
var
  W1252: TW1252;
  S: RawByteString;
begin
  W1252 := AData; // В этой строке выполняются действия, которые раньше выполнял у меня цикл - это обратные действия к тем, что выполняет Indy
  // Теперь копирование данных одним блоком в буфер
  SetLength(S, Length(W1252));
  Move(Pointer(W1252)^, Pointer(S)^, Length(W1252));
  // Помечаем, что данные на самом деле имеют кодировку 1251
  SetCodePage(S, 1251, False);
  // Ну и конвертация в Unicode
  Result := S;
end;


В отличие от этой, предыдущей:


function FixString(const AData: String): String;
  var
    S: RawByteString;
    X: Integer;
  begin
    SetLength(S, Length(AData));
    for X := 1 to Length(AData) do
      S[X] := AnsiChar(AData[X]);
    SetCodePage(S, 1251, False);
    Result := S;
  end;


Почему - не вникал. Также следующий код:


var
  Bytes: TIdBytes;
  S: AnsiString;
begin
  S := 'Европейская короткошерстная кошка: О ПОРОДЕ - Породы кошек - CATS-портал';
  SetLength(Bytes, Length(S));
  Move(Pointer(S)^, Bytes[0], Length(S));
  ShowMessage(AnsiString(BytesToString(Bytes, 0, Length(Bytes), en8Bit)));
end;


работает у меня нормально и без FixString, если писать:


  ShowMessage(AnsiString(BytesToString(Bytes, 0, Length(Bytes), TEncoding.GetEncoding(1251))));


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

18-12-2009 10:03 | Вопрос к автору: запрос дополнительной информации
Ребят, подскажите еще. Бьюсь третий день с аналогичной проблемой.
Ситуация у меня такая.
Вызваю метод IdHTTP.Head(URL)
с линком на файл. Получаю заголовки в IdHTTP.Response. Потом из заголовка Content-Disposition я вытягиваю имя запрашиваемого файла. Всё было хорошо на D7, а на D2009 вылезла
проблема с русским именами. Не могу понять в какой кодировке Инди мне их передаёт...
Метод от Александра Алексеева строку не меняет:( может что пропустил... сам не силён в кодировках, буду очень признателен за помощ!

14-12-2009 17:51 | Комментарий к предыдущим ответам
Решено - ступил.

14-12-2009 03:50 | Комментарий к предыдущим ответам
А как быть, если запрашиваемый документ в другой кодировке, нежели 1251?
Не могу привести в читаемый вид документ с русским тестом в utf-8.

27-02-2009 17:36 | Комментарий к предыдущим ответам
http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
1200
utf-16
Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications


Точно, каюсь, 1200 - это и есть Юникод

К слову сказать, формально Indy возвращает, конечно же, unicode-строку, полученную как конвертирование из кодировки 1252
Упс, вот эту фразу и не заметил в предыдущий раз, sorry

27-02-2009 00:03 | Комментарий к предыдущим ответам
>>> С маленькой поправкой: она трактуется вообще как win1200, ибо именно 1200 мы получим после использования функции StringCodePage (Delphi2009):
См.
>>> К слову сказать, формально Indy возвращает, конечно же, unicode-строку, полученную как конвертирование из кодировки 1252.

26-02-2009 09:39
Так win1200 - это есть Unicode (http://www.lingoes.net/en/translator/codepage.htm).
Как я понимаю, в этом и есть ошибка, что Инди возвращает это как уникод, а на самом деле там не уникод вовсе.

26-02-2009 08:06
А работает у вас (если работает), только благодаря невероятной случайности: ибо в строке SetLength(RBS, Length(s)); менеджер памяти выделил вам память ровно на том же месте, где была оригинальная строка, полученная Indy, до того момента, как он начал её переводить.
Мде, и правда что... Повторил эксперименты и пришёл к выводу, что это странности компилятора: неправильный код всё равно работает и приводит к правильному (!) результату

Поэтому в итоге мы получаем строку, в которой лежит строка (KOI8 или Win1251), но при этом она трактуется как Win1252.
С маленькой поправкой: она трактуется вообще как win1200, ибо именно 1200 мы получим после использования функции StringCodePage (Delphi2009):

Caption:=IntToStr(StringCodePage(IdHTTP.Get('http://ya.ru')));


26-02-2009 04:28 | Комментарий к предыдущим ответам
К слову сказать, формально Indy возвращает, конечно же, unicode-строку, полученную как конвертирование из кодировки 1252. Только вот в строку он загоняет байты как они пришли без конвертации. Поэтому в итоге мы получаем строку, в которой лежит строка (KOI8 или Win1251), но при этом она трактуется как Win1252.

Поэтому можно использовать и вот такой вариант:

function FixString(const AData: String): String;
type
  TW1252 = type AnsiString(1252);
var
  W1252: TW1252;
  S: RawByteString;
begin
  W1252 := AData; // В этой строке выполняются действия, которые раньше выполнял у меня цикл - это обратные действия к тем, что выполняет Indy
  // Теперь копирование данных одним блоком в буфер
  SetLength(S, Length(W1252));
  Move(Pointer(W1252)^, Pointer(S)^, Length(W1252));
  // Помечаем, что данные на самом деле имеют кодировку 1251
  SetCodePage(S, 1251, False);
  // Ну и конвертация в Unicode
  Result := S;
end;


25-02-2009 17:26 | Комментарий к предыдущим ответам
имелось в виду: объем сжатой текстовой информации, эквивалентный большой фотографии, велик.

25-02-2009 17:24 | Комментарий к предыдущим ответам
Добавьте сюда еще кучу мелко-мобильных устройств, которые тоже должны уметь шарить в вебе, и о LZW можно будет забыть.

JPEG на финальном этапе сжимает коэффициенты ДКП примерно этим алгоритмом (LZW). Повторюсь, 1 приличная картинка содержит столько текста, сколько надо читать месяц. Поэтому, любое устройство, которое способно показывать сжатые картинки, справится и со сжатыми текстами уже точно. Из текстов ведь видео не делают :) (хотя есть такие увлечения у народа)

25-02-2009 05:23
>>> От себя хочу добавить к этому решению, что оно прекрасно работает и без этого участка (избыточный код)
Это вы, батенька, изрядно погорячились.
Если вы посмотрите на свой новый код, то увидите, что строка RBS у вас никак не связана с S. И данные из S в RBS не попадают вообще!
А работает у вас (если работает), только благодаря невероятной случайности: ибо в строке SetLength(RBS, Length(s)); менеджер памяти выделил вам память ровно на том же месте, где была оригинальная строка, полученная Indy, до того момента, как он начал её переводить.

Ещё раз, по строкам:

  function FixString(const AData: String): String;
  var
    S: RawByteString;
    X: Integer;
  begin
    SetLength(S, Length(AData));    // выделили память под ANSI-буфер
    for X := 1 to Length(AData) do  // переносим данные из вида 00A400B700E700D5 в A4B7E7D5
      S[X] := AnsiChar(AData[X]); 
    SetCodePage(S, 1251, False);    // пометим, что данные A4B7E7D5имеют кодировку Win1251.
                                    // False указывает на то, что сами данные менять не надо -
                                    // мы просто указываем, в какой они кодировке
    Result := S;                    // здесь компилятор автоматически преобразует строку из ANSI/Win1251 в unicode
  end;


25-02-2009 05:03 | Комментарий к предыдущим ответам
UTF8, как я понял, предназначен в основном для веба
Для С. Там 0 - конец строки. utf8 нулевых байтов не содержит.

25-02-2009 04:37
От себя хочу добавить к этому решению, что оно прекрасно работает и без этого участка (избыточный код):

  for X := 1 to Length(AData) do
      S[X] := AnsiChar(AData[X]);




То есть окончательный вариант выглядит так:

// Функция
function E1251(const s: string): string;
var RBS: RawByteString;
begin
  SetLength(RBS, Length(s));
  SetCodePage(RBS, 1251, false);
  Result:=RBS;
end;

// Пример использования
  Memo.Text:=E1251(IdHTTP.Get('http://ya.ru'));


25-02-2009 04:15 | Комментарий к предыдущим ответам
Ура! Александр Алексеев, спасибо за подробное раследование и обстоятельное разъяснение причин странного поведения "Индейки" :)

С данной проблемой (вместо 1252 получаем набор символов в 1251 через IdHTTP) столкнулся ещё месяца 3-4 назад, переворошил кучу статей в интернете и примеров с изменением кодировок в D2009, прочитал про SetCodePage, перебрал все возможные варианты... Потратил на изучение информации два дня, окончательно запутался в "дельфийских юникодах", а в итоге от безысходности написал самодельную функцию "1251 -> 1252" %-) Вот этот ужас, для сравнения с элегентным решением из Ответа от 02-02-2009 09:09, самому страшно:

function windows_1252towindows_1251(InString : string): string;
var i: word;
begin
  Result:=InString;
  for i:=1 to Length(InString) do
  case InString[i] of
  'a': Result[i]:='а''a': Result[i]:='б''a': Result[i]:='в';
  'a': Result[i]:='г''a': Result[i]:='д''a': Result[i]:='е';
  '?': Result[i]:='ё''?': Result[i]:='ж''c': Result[i]:='з';
  'e': Result[i]:='и''e': Result[i]:='й''e': Result[i]:='к';
  'e': Result[i]:='л''i': Result[i]:='м''i': Result[i]:='н';
  'i': Result[i]:='о''i': Result[i]:='п''?': Result[i]:='р';
  'n': Result[i]:='с''o': Result[i]:='т''o': Result[i]:='у';
  'o': Result[i]:='ф''o': Result[i]:='х''o': Result[i]:='ц';
  '?': Result[i]:='ч''o': Result[i]:='ш''u': Result[i]:='щ';
  'u': Result[i]:='ъ''u': Result[i]:='ы''u': Result[i]:='ь';
  'y': Result[i]:='э''?': Result[i]:='ю''y': Result[i]:='я';

  'A': Result[i]:='А''A': Result[i]:='Б''A': Result[i]:='В';
  'A': Result[i]:='Г''A': Result[i]:='Д''A': Result[i]:='Е';
  '?': Result[i]:='Ё''?': Result[i]:='Ж''C': Result[i]:='З';
  'E': Result[i]:='И''E': Result[i]:='Й''E': Result[i]:='К';
  'E': Result[i]:='Л''I': Result[i]:='М''I': Result[i]:='Н';
  'I': Result[i]:='О''I': Result[i]:='П''?': Result[i]:='Р';
  'N': Result[i]:='С''O': Result[i]:='Т''O': Result[i]:='У';
  'O': Result[i]:='Ф''O': Result[i]:='Х''O': Result[i]:='Ц';
  '?': Result[i]:='Ч''O': Result[i]:='Ш''U': Result[i]:='Щ';
  'U': Result[i]:='Ъ''U': Result[i]:='Ы''U': Result[i]:='Ь';
  'Y': Result[i]:='Э''?': Result[i]:='Ю''?': Result[i]:='Я';
  end;
end;



Сегодня снова решил изучить ВСЁ про Юникод и про работу с ним в Delphi 2009, прочитал обзор-руководство "Delphi в мире Юникода (в трёх частях)"от Embarcadero CodeGear,
http://edn.embarcadero.com/article/38446
http://edn.embarcadero.com/article/38582
http://edn.embarcadero.com/article/38703

множество статей в Википедии про кодировки, а потом, о чудо! в поисковике наткнулся на этот вопрос на славном королевстве :))) Приятный сюрприз


Ещё бы в Embarcadero подправили Indy, чтобы не приходилось ииспользовать обходные пути :( Надеюсь в следующей версии Delphi они это учтут

PS: ещё раз спасибо за решение проблемы

22-02-2009 04:16 | Комментарий к предыдущим ответам
Писал парсер. Столкнуся с этой же проблемой.
Ответ от 02-02-2009 09:09 мне помог. Спасибо большое! :)

03-02-2009 13:28 | Комментарий к предыдущим ответам
Хотя если подумать, наверное там важнее скорость парсинга тегов, и объемы занимаемой памяти. В случае с UTF8 большая часть символов будет представлена одним байтом.

03-02-2009 13:19 | Комментарий к предыдущим ответам
То, о чем вы говорите, называется UTF16 и UTF32 :) UTF8, как я понял, предназначен в основном для веба, где по сей день существуют медленные модемные соединения. Добавьте сюда еще кучу мелко-мобильных устройств, которые тоже должны уметь шарить в вебе, и о LZW можно будет забыть.

03-02-2009 11:42 | Сообщение от автора вопроса
Большое спасибо. Намотал "на ус"...
:-)

P.S. Еще где-то в начале 90-х, когда я поставил Windows 3.0 и узнал, что у него стандартная кодировка Win-1251, а не OEM866, я удивлялся, зачем они буквы с места на место переставляют и создают проблемы. А если учесть, что есть еще туча национальных кодировок в мире, то, наверное, и они переделались в новые с выходом винды. И сказал знакомому, а че бы 16 битами не кодировать букву и сделать одну кодировку вообще?

Но когда появилась UTF-8, я вообще офигел - это ж надо додуматься сделать переменное кол-во байт на символ! От 1 до 6, если мне не изменяет память.

Вот, например, при росте цветности изображений просто брали 1, 2, 4, 8, 16, 24, 32, 64 бита и все. Если надо кодировать, то есть разные эффективные алгоритмы сжатия, которые делают это именно оптимально (GIF, PNG), а если не надо - то банально несколько несколько бит на точку и все.

Если сравнивать с UTF-8, то можно было бы сделать так: "для совместимости со старыми палитровыми режимами мы будем кодировать родные для них цвета в 4 или 8 бит, а остальные большим числом бит, до 128, скажем. А фиг ли, пусть потом программеры мучаются. А еще сделаем 50 кодировок - одну для фоток, другую для гравюр, третью для факсов, четвертую для детских рисунков фломастерами..." Именно такой принцип и заложен в UTF-8. Кто мешает сделать одну кодировку на все случаи жизни, а для передачи/хранения сжимать LZW и т.д.

И все это при том, что объем текстовых данных обычно меньше графических в миллионы раз в реальных применениях (Библия на англ. языке в 8-битной кодировке занимает 5Мб, меньше чем одна картинка несжатая в 1600x1200x24). Если мало 16 бит, пусть берут 32 и делают что хотят с ними - столько букв на свете нету :))) Не понятно мне, зачем весь мир нагибать мучаться с разными кодировками.

03-02-2009 11:13
>>> это несовместимость Indy10 с уникодом или это нормально?
Я не знаю, что это. Если смотреть на наличие директив для D2009 в исходниках Indy, то видно, что над unicode явно работали. Может быть, это баг. А может быть, это так и должно быть. Я не знаю.

03-02-2009 11:11
>>> Александр, подскажите, если не трудно, а в какой кодировке возвращался результат Get?
Насколько я понимаю - ни в какой. Indy в этом сценарии кодировку не учитывает никак. Кодировка передаётся только в ContentTypeStrToEncoding, из которой может выходить только en8bit или enUTF8. Поскольку у нас не UTF8, то значит, по мнению Indy, кодировка - en8bit.
Байты контента просто вслепую загонялись в строку string. Так, байт $A4 становился unicode-символом #$00A4. Это может и работало в D2007, потому что там байт $A4 становился Ansi-символом #$A4 - что и требовалось.
Соответственно, решение: сделать это же в обратную сторону, т.к. откинуть старший байт и получить Ansi-символ #$A4, а затем пометить всю строку нужной кодировкой (в нашем случае - 1251), конвертирование же в unicode выполнится автоматически при присвоении Result-а в FixString.

03-02-2009 10:48 | Сообщение от автора вопроса
Чудо! Работает! :)
Александр, подскажите, если не трудно, а в какой кодировке возвращался результат Get?
И вообще, это несовместимость Indy10 с уникодом или это нормально?

02-02-2009 09:09
А, следовательно, решение выглядит вот так:

procedure TForm52.Button2Click(Sender: TObject);

  function FixString(const AData: String): String;
  var
    S: RawByteString;
    X: Integer;
  begin
    SetLength(S, Length(AData));
    for X := 1 to Length(AData) do
      S[X] := AnsiChar(AData[X]);
    SetCodePage(S, 1251, False);
    Result := S;
  end;

var
  S: String;
begin
  S := IdHTTP1.Get('http://cat.mau.ru/eur/');
  S := FixString(S);
  ShowMessage(S);
end;



Разумеется, вместо 1251 надо подставлять нужную кодировку.

02-02-2009 08:59 | Комментарий к предыдущим ответам
Прошу прощения, не заметил URL.

Вот, что, похоже, происходит сейчас в Indy:

var
  Bytes: TIdBytes;
  S: AnsiString;
begin
  S := 'Европейская короткошерстная кошка: О ПОРОДЕ - Породы кошек - CATS-портал';
  SetLength(Bytes, Length(S));
  Move(Pointer(S)^, Bytes[0], Length(S));
  ShowMessage(AnsiString(BytesToString(Bytes, 0, Length(Bytes), en8Bit)));
end;

02-02-2009 08:52 | Вопрос к автору: запрос дополнительной информации
А должно быть?

31-01-2009 11:34 | Сообщение от автора вопроса
Вот начало возвращаемой строки:

<html><head>'#$D#$A'<title>Aa?iiaeneay ei?ioeioa?noiay eioea: I II?IAA - Ii?iau eioae - CATS-ii?oae</title>'#$D#$A'<meta name=description content='Eaoaeia ii?ia eioae. Aa?iiaeneay eioea: i ii?iaa aa?iiaeneay, enoi?ey ii?iau, ie?anu aa?iiaeneie eioee, noaiaa?o aa?iiaeneie eioee, i?iaa?a eioyo, oioi aa?iiaeneeo eioae'>'#$D#$A'<meta name=keywords content="eioee ii?iau aa?iiaeneay eo aa?iiaeneay eioea ii?iaa, aa?iiaeneay e/o i?iaa?a eioyo eur ieoiiieee eioae cats-portal cats-ii?oae">

31-01-2009 11:24 | Сообщение от автора вопроса
Извините, был в отлучке :)

Используется функция
function TIdCustomHTTP.Get(AURL: string): string;

из модуля
"C:\Program Files (x86)\CodeGear\RAD Studio\6.0\source\Indy\Indy10\Protocols\IdHTTP.pas"

сборка дельфи
Delphi 2009 12.0.3210.17555

Содержимое строки - результат запроса (страница в кодировке windows-1251):
html := http.Get('http://cat.mau.ru/eur/');

После записи строки html в файл Вордом нельзя подобрать для него кодировку. Млин, понаворотили блин, хоть на D2007 переходи :(

Валера.

29-01-2009 04:10 | Вопрос к автору: запрос дополнительной информации
Вопрос автору вопроса: а что находится в строке? Покажите.
Попробуйте также сохранить её в текстовый файл и поподбирать кем-нибудь кодировку (например, Word-ом).

P.S. А вы, чисто случайно, не Indy 9 используете?

29-01-2009 04:08 | Комментарий к предыдущим ответам
>>> А флаг DOTNET_OR_TEncoding там разве не установлен?
Опс, моя вина. Действительно, он установлен:

//Delphi 13 - Delphi 2009 (Tiburon)
{$IFDEF VER200}
  {$DEFINE UNICODESTRING} // 'String' type is Unicode now
  {$DEFINE TEncoding}
  {$DEFINE TCharacter}
  {$DEFINE DOTNET_OR_TEncoding}  // <- вот
  {$DEFINE USEINLINE}
  {$DEFINE VCL4ORABOVE}
  {$DEFINE VCL5ORABOVE}
  {$DEFINE VCL6ORABOVE}
  {$DEFINE VCL7ORABOVE}
  {$DEFINE VCL8ORABOVE}
  {$DEFINE VCL9ORABOVE}
  {$DEFINE VCL10ORABOVE}
  {$DEFINE VCL11ORABOVE}
  {$DEFINE VCL12ORABOVE}
  {$DEFINE VCL13ORABOVE}
  {$DEFINE VCL13}
  {$DEFINE DELPHI13}
  {$DEFINE OPTIONALPARAMS}
  {$DEFINE SAMETEXT}
  {$DEFINE ALLOW_NAMED_THREADS}
  {$IFNDEF IDFREEONFINAL}
    {$DEFINE REGISTER_EXPECTED_MEMORY_LEAK}
  {$ENDIF}
  {$DEFINE TFormatSettings}
  {$DEFINE CPUI386}
  {$DEFINE ENDIAN_LITTLE}
  {$DEFINE CPU32}
  {$IFNDEF CIL}
    {$DEFINE WIDGETVCLLIKE} // LCL included.
    {$DEFINE WIDGETVCLLIKEORKYLIX}
    {$DEFINE WIDGETVCL}
    {$DEFINE VCL60PLUS}
  {$ENDIF}
{$ENDIF}



Не подумал про это - по названию он у меня с D2009 никак не ассоциируется.

Тогда получается, что используется первая ветка, а там либо цикл, либо:

function GetEncoder(AEncoding: TIdEncoding): SysUtils.TEncoding;
{$IFDEF USEINLINE}inline;{$ENDIF}
begin
  case AEncoding of
    en7Bit: Result := TEncoding.ASCII;
    enUTF8: Result := TEncoding.UTF8;
    en8Bit: begin
        if Id8BitEncoder = nil then begin
          Id8BitEncoder := TEncoding.GetEncoding(1252); // Windows-1252
        end;
        Result := Id8BitEncoder;
      end;
    else    Result := nil;
  end;
end;



Т.е. опять что-то странное. Всегда используется либо UTF8, либо Windows-1252.

29-01-2009 03:35 | Комментарий к предыдущим ответам
А флаг DOTNET_OR_TEncoding там разве не установлен? Судя по названию он как раз для D2009.

29-01-2009 01:46
Нырнул сейчас в исходники Indy.
Что-то там, похоже, намутили.

Get действительно вызывает и принимает unicode-строку.
При этом его работа сводится к:

    Result := ReadStringFromStream(LStream, -1,
      ContentTypeStrToEncoding(Response.FContentType));



Где ContentTypeStrToEncoding возвращает всего-лишь en8bit или enUTF8:

  TIdEncoding = (enDefault, en7Bit, enUTF8, en8Bit);

function ContentTypeStrToEncoding (const aContentType: string): TIdEncoding;
//TODO:  Figure out what should happen with Unicode content type.
var
  LCharSet: String;
begin
  LCharSet := ExtractHeaderSubItem(aContentType, 'CHARSET');  {do not localize}
  if LCharSet <> '' then
  begin
    if PosInStrArray(LCharSet, ['UTF-8', 'UTF8'], False) <> -1 then begin
      Result := enUTF8;
      Exit;
    end;
  end;
  {JPM - I have decided to temporarily make this en8bit because I'm concerned
  about how binary files will be handled by the en7bit encoder (where there may
  be 8bit byte-values.  In addition, there are numerous charsets for various
  languages and code that does some special mapping for them would be a mess.}

  Result := en8bit; //en7Bit;
end;



А ReadStringFromStream выглядит так:

function ReadStringFromStream(AStream: TStream; ASize: Integer = -1;
  const AEncoding: TIdEncoding = en7Bit): string;
var
  LBytes: TIdBytes;
begin
  ASize := TIdStreamHelper.ReadBytes(AStream, LBytes, ASize);
  Result := BytesToString(LBytes, 0, ASize, AEncoding);
end;



Всё конвертирование находится в BytesToString:

function BytesToString(const AValue: TIdBytes; const AStartIndex: Integer;
  const ALength: Integer = -1; const AEncoding: TIdEncoding = en7Bit): string; overload;
var
  LLength: Integer;
  {$IFDEF DOTNET_OR_TEncoding}
  i : Integer;
  {$ENDIF}
begin
  ValidEncoding(AEncoding); //This raises an exception if the AEncoding parameter is enDefault
  LLength := IndyLength(AValue, ALength, AStartIndex);
  if LLength > 0 then
  begin
    {$IFDEF DOTNET_OR_TEncoding}
    {
    IMPORTANT!!!

  We do not use the TEncoding interface at all for en8bit.  The Windows-1252
    code page translates bytes from range #80-#9F to Unicode so that you can
    display them.  Unfortunately, that behavior creates problems for non-printable
    binary (9bit) data where translation to displayable strings is not desirable.
    }

    if AEncoding = en8bit then
    begin
      SetLength( Result, LLength);
      for i := AStartIndex to LLength - 1 do begin
        Result[ i + 1] := Char(AValue[ i]);
      end;
    end
    else
    begin
      Result := GetEncoder(AEncoding).GetString(AValue, AStartIndex, LLength);
    end;
    {$ELSE}
    if AEncoding = enUTF8 then begin
      Result := UTF8BytesToString(AValue, AStartIndex, LLength);
    end else
    begin
      // For VCL we just do a byte to byte copy with no translation. VCL uses ANSI or MBCS.
      // With MBCS we still map 1:1
      SetLength(Result, LLength);                        // <- !!!! И это UnicodeString?!!! 
      Move(AValue[AStartIndex], Result[1], LLength);      // <- !!!!
    end;
    {$ENDIF}
  end else begin
    Result := '';
  end;
end;



Явный баг. Похоже, индю просто перекомпилили, без изменений кода.

Попробуйте произвести со строкой такое преобразование:

function FixString(const AData: String): String;
var
  Data: RawByteString;
begin
  if AData <> '' then
  begin
    SetLength(Data, Length(AData));
    Move(Pointer(AData)^, Pointer(Data)^, Length(AData));
    SetCodePage(Data, 1251); // <- указать нужную кодировку
    Result := Data;
  end
  else
    Result := '';
end;

var
  html: String;
begin
  html := FixString(http.Get(labelURL.Caption));
end;



Или (не совсем корректный вариант, но для теста сойдёт):

function FixString(const AData: String): String;
var
  Data: AnsiString;
begin
  if AData <> '' then
  begin
    SetLength(Data, Length(AData));
    Move(Pointer(AData)^, Pointer(Data)^, Length(AData));
    Result := Data; // Кодировка - всегда текущая
  end
  else
    Result := '';
end;

var
  html: String;
begin
  html := FixString(http.Get(labelURL.Caption));
end;



Обязательно отпишитесь, ибо вопрос сильно актуальный.

28-01-2009 14:57 | Сообщение от автора вопроса
Поставил false, потом true - перекодировки нет. Но как я понимаю, true должна перекодировать, а не false.

А вот всякие OEMToANSI и т.д....
я пробовал - там мура какая-то получается вообще.

Неужели я один наступил на грабли кодировок из 1251 в дельфовое представление?

28-01-2009 14:01
У SetCodePage возможен третий параметр, он должен быть True если вы хотите перекодировать строку в другую кодировку, а если нужно просто указать правильную кодировку для строки, то False. По умолчанию вроде бы ставится True. Попробуйте в своем коде поставить False. Возможно у вашей строки просто неправильно указана кодировка.

28-01-2009 13:40 | Сообщение от автора вопроса
Вот определение функции Инди в Д2009:
function Get(AURL: string): string; overload;

string ведь один.

Че делать-то? :)

28-01-2009 13:30 | Вопрос к автору: запрос дополнительной информации
А вот интересно, Indy тоже для Delphi 2009 переписали под Unicode? В 10 версии Indy эта функция возвращала ANSI-строку, если не ошибаюсь.

28-01-2009 12:29 | Сообщение от автора вопроса
Не помогло. Писал так:

var
  html: RawByteString;
begin
  html := http.Get(labelURL.Caption);
  SetCodePage(html, 1251);
end;

html никак не изменяется.
Есть мысли какие еще?

28-01-2009 01:31
Может так: »вопрос КС №67996« ?

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Вода мокрая или сухая?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования