Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 11.08.2011, 22:42
Snake22 Snake22 вне форума
Активный
 
Регистрация: 20.02.2011
Сообщения: 374
Репутация: 744
По умолчанию unicode в ansi и обратно

помогите с такой задачей. есть юникод файл (UCS-2 Little Endian),с длинной символа 4 байта. нужно перекодировать в анси чтоб загрузить его в мемо,поредактировать и соханить обратно в юникод.
к сожалению в инете нашел только пример для двухбайтных,а мне 4 нужно.
в архиве такая программа,с двухбайтной длинной.и два файла один который мне нужен (имя 4.тхт) и второй который прогамма делает (2.тхт).
может кто сможет что переделать? или подскажет как что
Вложения
Тип файла: rar WorkWithUnicodeFile.rar (7.2 Кбайт, 45 просмотров)
Ответить с цитированием
  #2  
Старый 11.08.2011, 23:07
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Дай текст в UCS2 (4-байта).
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
  #3  
Старый 11.08.2011, 23:43
Snake22 Snake22 вне форума
Активный
 
Регистрация: 20.02.2011
Сообщения: 374
Репутация: 744
По умолчанию

Цитата:
Сообщение от angvelem
Дай текст в UCS2 (4-байта).
в архиве файл с именем 4.тхт такой
Ответить с цитированием
  #4  
Старый 11.08.2011, 23:47
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Там обычная UTF16LE строка (2-х байтовая). Кодируется стандартно. Вот в 2.txt строка не самая стандартная - без заголовка.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.

Последний раз редактировалось angvelem, 11.08.2011 в 23:50.
Ответить с цитированием
  #5  
Старый 11.08.2011, 23:52
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Я пользовался этим:
Код:
unit convert;

interface

const
  UTF16BE = $FFFE;
  UTF16LE = $FEFF;

function DetectUTF16LEBOM(const P: PChar; const Size: Integer): Boolean;
function DetectUTF16BEBOM(const P: PChar; const Size: Integer): Boolean;
function UTF16ToUTF8(const S : WideString; Count : Integer; var utf : Boolean; Swap : Boolean = False) : AnsiString;

implementation

//----------------------------------------------------------
  
type
  UCS2 = Word;
  UCS4 = Cardinal;

const
  MaximumUCS4		: UCS4 = $7FFFFFFF;
  ReplacementCharacter	: UCS4 = $0000FFFD;

function DetectUTF16LEBOM(const P: PChar; const Size: Integer): Boolean;
begin
  Result := Assigned(P) and (Size >= Sizeof(WideChar)) and (PWideChar(P)^ = WideChar(UTF16LE));
end;

function DetectUTF16BEBOM(const P: PChar; const Size: Integer): Boolean;
begin
  Result := Assigned(P) and (Size >= Sizeof(WideChar)) and (PWideChar(P)^ = WideChar(UTF16BE));
end;

function SwapUTF16Endian(const P : Cardinal) : Cardinal;
begin
  Result := ((Ord(P) and $FF) shl 8) or (Ord(P) shr 8);
end;

function ConvertSurrogate(S1, S2 : UCS2) : UCS4;
// Converts a pair of high and low surrogate into the corresponding UCS4 character.
const
  SurrogateOffset = ($D800 shl 10) + $DC00 - $10000;
begin
  Result := Word(S1) shl 10 + Word(S2) - SurrogateOffset;
end;

function UTF16ToUTF8(const S : WideString; Count : Integer; var utf : Boolean; Swap : Boolean = False) : AnsiString;
// Converts the given Unicode text (which may contain surrogates) into
// the UTF-8 encoding used for the HTML clipboard format.
const
  FirstByteMark: array[0..6] of Byte = ($00, $00, $C0, $E0, $F0, $F8, $FC);
var
  Ch           : UCS4;
  I, J, T      : Integer;
  BytesToWrite : Cardinal;
begin
  Result := '';
  utf := True;
  if (Count = 0) then
    Exit;
  begin
    // Make room for the result. Assume worst case, there are only short texts to convert.
    SetLength(Result, 6 * Count);
    T := 1;
    I := 1;
    BytesToWrite := 0;
    while I <= Count do
    begin
      Ch := UCS4(S[i]);
      if Swap then				// for UTF16BE
	Ch := SwapUTF16Endian(Ch);

      if (Hi(Ch) = 0) and (Lo(Ch) >= $C0) then	// for wild (mad) record with codepage cp1251
      begin
	BytesToWrite := 1;
	Result[T] := AnsiChar(Lo(Ch));
	inc(T, BytesToWrite);
	inc(I);
	utf := False;
	Continue;
      end
      else
      begin
	if (Ch and $FFFFF800) = $D800 then	// Is the character a surrogate?
	begin
	  inc(I);
	  // Check the following char whether it forms a valid surrogate pair with the first character.
	  if (I <= Count) and ((UCS4(S[i]) and $FFFFFC00) = $DC00) then
	    Ch := ConvertSurrogate(UCS2(Ch), UCS2(S[i]))
	  else // Skip invalid surrogate value.
	    Continue;
	end;

	if Ch < $80 then
	  BytesToWrite := 1
	else if Ch < $800 then
	  BytesToWrite := 2
	else if Ch < $10000 then
	  BytesToWrite := 3
	else if Ch < $200000 then
	  BytesToWrite := 4
	else if Ch < $4000000 then
	  BytesToWrite := 5
	else if Ch <= MaximumUCS4 then
	  BytesToWrite := 6
	else
	begin
	  BytesToWrite := 2;
	  Ch := ReplacementCharacter;
	end;
      end;
      for J := BytesToWrite downto 2 do
      begin
	Result[T + J - 1] := AnsiChar((Ch or $80) and $BF);
	Ch := Ch shr 6;
      end;
      Result[T] := AnsiChar(Ch or FirstByteMark[BytesToWrite]);
      inc(T, BytesToWrite);

      inc(I);
    end;
    SetLength(Result, T - 1); // set to actual length
  end;
end;

end.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
  #6  
Старый 12.08.2011, 00:09
Snake22 Snake22 вне форума
Активный
 
Регистрация: 20.02.2011
Сообщения: 374
Репутация: 744
По умолчанию

Цитата:
Сообщение от angvelem
Там обычная UTF16LE строка (2-х байтовая). Кодируется стандартно. Вот в 2.txt строка не самая стандартная - без заголовка.
хм у меня нотпад++ показывает что юникод и стандартный блокнот.
А вот этот файл,
Вложения
Тип файла: txt 101F8847.txt (2.1 Кбайт, 8 просмотров)
Ответить с цитированием
  #7  
Старый 12.08.2011, 00:12
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

То же самое, UTF16LE строка (2-х байтовая).
В 2.txt unicode, но встречается такой формат гораздо реже.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.

Последний раз редактировалось angvelem, 12.08.2011 в 00:15.
Ответить с цитированием
  #8  
Старый 12.08.2011, 00:57
Аватар для Karsh
Karsh Karsh вне форума
Активный
 
Регистрация: 22.09.2007
Адрес: SPb
Сообщения: 228
Версия Delphi: 7, 2009, XE2
Репутация: 70
По умолчанию

Snake22, как я понял, ваша программа нормально считывает файл 2.txt, но "глючит" с файлом 4.txt, и поэтому вы решили спросить совета тут? Все дело в том, что в файле 2.txt нет сигнатуры (или как там она называется), а в 4.txt - она есть, а считывание информации из файла идет с 0, другими словами, при считывании инфы из 2 в строку идет юникодовый текст (с ним проблем нет), а вот из 4 - сигнатура и только после нее текст (а вот тут и возникает проблема). Вам нужно перед WideCharLenToString убрать из начала строки сигнатуру, если она есть.
А тов. angvelem правильно сказал, оба текста в кодировке UTF16LE, только один без сигнатуры.

Кстати, для сохранения юникодовой информации в файл сначала нужно записать сигнатуру, а потом текст. Поверьте, так будет лучше для всех.)
По аналогии с вашей программой:
Код:
var
s: string;
...
s:= #FF#FE;
BlockWrite(f, PChar(s)^, 2);

И еще заметил:
Код:
BlockWrite(f, PWideChar(WStr)^, Length(WStr));
Тут нужно Length(WStr) умножить на два, т.к. Length выдаёт только кол-во букв, а в юникоде буква - 2 байта, а не 1 как в анси.
__________________
Начинающий программист уверен, что в 1 килобайте 1000 байт.
Законченный программист уверен, что в 1 километре 1024 метра.

Последний раз редактировалось Karsh, 12.08.2011 в 01:06.
Ответить с цитированием
  #9  
Старый 12.08.2011, 01:03
Snake22 Snake22 вне форума
Активный
 
Регистрация: 20.02.2011
Сообщения: 374
Репутация: 744
По умолчанию

Ладно,может будет сохранять в нужном формате.подскажите как это реализовать?
Я так понял представленный юнит конвертирует в ютф8? А чтоб сохранить,обратно в юникод как? (извиняюсь если где туплю,не оч разбираюсь)
Ответить с цитированием
  #10  
Старый 12.08.2011, 01:12
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Вот тебе архив со всем подряд на эту тему, ковыряй.
unicode
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.

Последний раз редактировалось angvelem, 12.08.2011 в 01:22. Причина: Не загромождать форум архивами
Ответить с цитированием
  #11  
Старый 12.08.2011, 01:14
Аватар для Karsh
Karsh Karsh вне форума
Активный
 
Регистрация: 22.09.2007
Адрес: SPb
Сообщения: 228
Версия Delphi: 7, 2009, XE2
Репутация: 70
По умолчанию

Цитата:
Сообщение от Karsh
...другими словами, при считывании инфы из 2 в строку идет юникодовый текст (с ним проблем нет), а вот из 4 - сигнатура и только после нее текст (а вот тут и возникает проблема). Вам нужно перед WideCharLenToString убрать из начала строки сигнатуру, если она есть.
Что-то я сам на счет это засомневался. Вроде и не нужно сигнатуру удалять, WideCharLenToString и так проглотит, просто уже не помню, последнее время кодю в D2009, а там особо с этим не заморачиваешься...
Цитата:
Сообщение от Snake22
Ладно,может будет сохранять в нужном формате.подскажите как это реализовать?
Просто добавьте перед
Код:
BlockWrite(f, PWideChar(WStr)^, Length(WStr));
то, что я писал в пред. сообщении и исправьте эту строку.
Цитата:
Я так понял представленный юнит конвертирует в ютф8?
Нет, UTF8 выглядит по-другому, и функция преобразования другая.
__________________
Начинающий программист уверен, что в 1 килобайте 1000 байт.
Законченный программист уверен, что в 1 километре 1024 метра.

Последний раз редактировалось Karsh, 12.08.2011 в 01:17.
Ответить с цитированием
  #12  
Старый 12.08.2011, 11:19
Snake22 Snake22 вне форума
Активный
 
Регистрация: 20.02.2011
Сообщения: 374
Репутация: 744
По умолчанию

Цитата:
Сообщение от Karsh
Кстати, для сохранения юникодовой информации в файл сначала нужно записать сигнатуру, а потом текст. Поверьте, так будет лучше для всех.)
По аналогии с вашей программой:
Код:
var
s: string;
...
s:= #FF#FE;
BlockWrite(f, PChar(s)^, 2);

И еще заметил:
Код:
BlockWrite(f, PWideChar(WStr)^, Length(WStr));
Тут нужно Length(WStr) умножить на два, т.к. Length выдаёт только кол-во букв, а в юникоде буква - 2 байта, а не 1 как в анси.
ага всем спасибо так и сделал,проблема решена.правда не стал длинну умножать на два,а то эта длинна кракозябрами заменялась и еще перед сохранением вручную пришлось удалять знак вопроса вначале текста в мемо,и при сохранении в строке
s:= #FF#FE;
BlockWrite(f, PChar(s)^, 2);
мой дельфи не понял что такое #FF#FE ,пришлось числами писать, и еще где цифра 2, заменил ее на 1,а то перед текстом пробел появлялся.теперь всё норм
Ответить с цитированием
  #13  
Старый 12.08.2011, 21:25
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Snake22
мой дельфи не понял что такое #FF#FE
Ну так читай справку.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 07:47.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025