Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.07.13;
Скачать: CL | DM;

Вниз

Чтение данных из файла UTF-8   Найти похожие ветки 

 
leonidus   (2008-06-13 11:58) [0]

Есть файл с данными в формате UTF8, мне нужно их прочесть и сконверировать в UTF16.

st_u:widestring;
f:textfile;

AssignFile(F, edit1.Text);
Reset(F);
readln(F,st_u);
st_u:= UTF8Decode(st_u);

В результате получаю st_u="", хотя при чтении из файла (readln(F,st_u)) строка содержит данные. Что же не так?


 
Anatoly Podgoretsky ©   (2008-06-13 12:40) [1]

Сейчас мы будем догадываться, что у тебя там в файле.
И почему st_u widestring. Справку конечно взглянуть ты в очередной раз не догадался.


 
palva ©   (2008-06-13 12:44) [2]

Строка для хранения UTF8 должна иметь тип String
Боюсь, что использовав WideString, вы заставили компилятор произвести ряд преобразований по умолчанию, что уничтожило ваши данные.


 
leonidus   (2008-06-13 15:25) [3]

s:string;
st_u:widestring;

AssignFile(F, edit1.Text);
Reset(F);
readln(F,s);
st_u:= UTF8Decode(s);

так же ничего не дает.

В файле словарь в определенном формате который мне нужно загрузить в TTNTStringList.


 
leonidus   (2008-06-13 15:29) [4]

Попробовал еще так:

s:string;
st_u:widestring;

AssignFile(FromF, edit1.Text);
Reset(FromF, 1);

BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
s:="";
for i:=1 to 20048 do
 s:=s+buf[i];

st_u:=UTF8Decode(s);

все тоже самое.


 
ZENsan ©   (2008-06-13 15:43) [5]


function TUtils.LoadWideStringFromFile(Filename: string; var s: WideString;
 Limit: Integer): Boolean;
var
 i: integer;
 f: file;
 Buf: Pointer;
 Size: Integer;
 Sign: Word;
 FileType, SignC: Byte;
 Offset: Integer;
begin
 Result := False;
 AssignFile(f, Filename);
 if not FileExists(Filename) then
   Exit;
 Buf := nil;
 try
   Reset(f, 1);
 except
   Exit;
 end;
 try
   if FileSize(F) > 2 then
     begin
       BlockRead(f, Sign, 2);
       Offset := 2;
     end
   else
     begin
       Sign := 0;
       Offset := 0;
     end;
   case Sign of
     $BBEF: //UTF-8
       begin
         BlockRead(f, SignC, 1);
         if SignC = $BF then
           begin
             FileType := 1;
             Offset := 3;
           end
         else
           FileType := 0;
       end;
     $FEFF: FileType := 2; //Little-Endian
     $FFFE: FileType := 3; //Big-endian
   else
     begin
       FileType := 0;
       Reset(f, 1);
       Offset := 0;
     end;
   end;
   Size := FileSize(f) - Offset;
   if Limit > -1 then
     if Size > Limit then
       Size := Limit;
   GetMem(Buf, Size + 2);
   FillChar(Buf^, Size + 2, 0);
   BlockRead(f, Buf^, Size);
   case FileType of
     0:
       begin
         s := UTF8Decode(PAnsiChar(Buf));
         if s = "" then
           s := PAnsiChar(Buf);
       end;
     1: s := UTF8Decode(PAnsiChar(Buf));
     2: s := PWideChar(Buf);
     3:
       begin
         for i := 1 to Length(S) do
           Word(S[i]) := (Word(S[i]) shl 8) and (Word(S[i]) shr 8);
         s := PWideChar(Buf);
       end;
   end;
   Result := True;
 finally
   if Assigned(Buf) then
     FreeMem(Buf);
 end;
 CloseFile(f);
end;


 
palva ©   (2008-06-13 16:15) [6]

Приведите входную строку в 16-ричном виде. (Длину и код каждого символа)
И выходую. (Ну, выходную строку мы уже знаем, она у вас пустая.)


 
leonidus   (2008-06-13 17:39) [7]

Это словарь от программы StarDict, вот его первые байты:
30 30 64 61 74 61 62 61 73 65 69 6E 66 6F 00 00

функция от ZENsan, возвращает строку до первого "00", т.е. :
"30 30 64 61 74 61 62 61 73 65 69 6E 66 6F" только в виде текста "00databaseinfo".

Как ни странно, но в файле нет маркеров $BBEF, $FEFF или $FFFE, но я точно знаю что файл в формате UTF-8.


 
ZENsan ©   (2008-06-13 17:43) [8]

У тебя UTF-8 without BOM.


 
ZENsan ©   (2008-06-13 17:45) [9]

измени просто функцийю если она тебе подходит немного и будет брать строку и после 00..

А когда нет бома, просто делай UTF8Decode и подавай строку эту.


 
leonidus   (2008-06-13 18:04) [10]

ZENsan так и не понял что нужно в вашей функции изменить, она вроде не ищет "00" для для завершения своей работы...

и можно "расшифровать" фразу "А когда нет бома, просто делай UTF8Decode и подавай строку эту." ?


 
palva ©   (2008-06-13 18:29) [11]


> leonidus   (13.06.08 17:39) [7]

У меня ваша строка преобразуется правильно:
Непонятно, почему у вас в результате преобразования была пустая строка. Можете попробовать следующий код:

{$APPTYPE CONSOLE}
var
 s: String;
 w: WideString;
begin
 s :="00databaseinfo"#0#0;
 w := UTF8Decode(s);
 WriteLn(Length(w));  // 16
 WriteLn(Ord(w[16])); // 0
end.

Может быть, я вас неправильно понял. Объясните точнее, что означают ваши слова в посте [3]
> так же ничего не дает.


 
Anatoly Podgoretsky ©   (2008-06-13 18:58) [12]

> leonidus  (13.06.2008 17:39:07)  [7]

Это не UTF8


 
leonidus   (2008-06-13 19:13) [13]

palva дело в том что файл состоит больше чем из одного слова 00databaseinfo, а если его открывать функцией [5], то на выходе только "00databaseinfo".

А идея вот в чем я пишу конвертер словарей StarDict в свой более простой формат, по спецификации формата словарей StarDict, словарь состоит из индексного файла и файла данных. Я сейчас разбираюсь с индексным. Он в формате UTF8 (был бы UTF16 я бы без проблем открыл его средствами библиотеки TNT) содержит последовательность заголовков словарных статей , маркер конца словарной статьи это символ "00", далее идут 4 байта смещения и 4 байта длины словарной статьи, потом следующий заголовок словарной статьи и так до конца индексного файла. Следовательно первое что мне нужно, это прочесть весь индексный файл в память (я помещаю его в строку String), после чего уже работаю с ней как с массивом. Но затем мне нужно данные записать в TTntStringList после чего сохранить эту структуру на диск но для этого UTF8 нужно преобразовать в UTF16 не потеряв при этом "юникодность" т.е. словарь может содержать не только англ. и русские бурвы но и например немецкие или испанские.


 
leonidus   (2008-06-13 19:17) [14]

Анатолий, мне нравится ваша лаконичность, но было бы здорово если бы она подпитывалась фактами. Я открываю файл через программу ListEdit, она определяет кодировку WIN(RUS) при этом не отображая скажем немецкие умляуты, но если я принудительно высталяю UTF-8, то все слова отображаются корректно, из чего я делаю вывод что кодировка документа именно UTF-8. что подтверждает и документация
http://stardict.sourceforge.net/StarDictFileFormat требующая от словаря именно такой кодировки.


 
palva ©   (2008-06-13 19:37) [15]

leonidus   (13.06.08 19:13) [13]
Ну то есть вопрос о неправильной работе функции UTF8Decode снят.


 
Anatoly Podgoretsky ©   (2008-06-13 19:39) [16]

> leonidus  (13.06.2008 19:17:14)  [14]

Попробуй сам преобразовать свои хекс коды в ANSI и сам увидишь.


 
leonidus   (2008-06-13 19:56) [17]

вот файл с которым борюсь:
http://www.realsofts.com/fr-ru-synt.zip


 
Anatoly Podgoretsky ©   (2008-06-13 21:37) [18]

А сюда привестм, что несколько байтов с UTF8 как просили не можешь?


 
palva ©   (2008-06-13 21:56) [19]


> вот файл с которым борюсь:

С файлом надо не бороться, с ним надо работать. Только сначала нужно освоить инструмент, которым работаете. Тогда это и будет кропотливая и нудная, но работа, а не борьба. Инструмент освоить здесь вам пожалуй что и помогут. А вот разбираться с файлом вряд ли будут, даже если вы будет уверять, что UTF8Decode не работает.


 
leonidus   (2008-06-13 22:14) [20]

[18] так я же приводил:
30 30 64 61 74 61 62 61 73 65 69 6E 66 6F 00 00


 
Anatoly Podgoretsky ©   (2008-06-13 22:27) [21]

> leonidus  (13.06.2008 22:14:20)  [20]

Это не UTF8


 
leonidus   (2008-06-13 22:30) [22]

ок, Анатолий тогда подскажите как прочесть эти данные и записать в WideString


 
palva ©   (2008-06-13 22:52) [23]

То, что вы описывали в [13] не очень подходит для чтения текстовыми функциями ReadLn. Для двоичного чтения используйте функцию BlockRead, либо другой метод чтения при помощи TFileStream. Но здесь, конечно, вам надо освоиться с чтением строки или целого числа из файла при помощи двоичного чтения.


 
McSimm ©   (2008-06-13 23:55) [24]


> Это не UTF8

почему же, это может быть UTF8 - все что до 7F кодируется одним байтом.


 
leonidus   (2008-06-13 23:57) [25]

Я пробовал и через BlockRead:

function StringToHex(const Source: String): String;
var i, Len: Integer;
begin
 Result := "";
 Len := Length(Source);
 for i := 1 to Len do
   Result := Result + IntToHex(Ord(Source[i]), 2) + " ";
end;

var
Buf: array[1..20048] of Char;
st,idx:string;
FromF: file;

AssignFile(FromF, edit1.Text);
Reset(FromF, 1);
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);

st:="";
for i:=1 to 20048 do
 st:=st+buf[i];
idx:=idx+st;

st:=StringToHex(st);
idx_hex:=idx_hex+st;
until (NumRead = 0);
CloseFile(FromF);

В результате получаю текстовую строку:
idx_hex=30 30 64 61 74 61 62 61 73 65 69 6E 66 6F 00 00 ....
из которой извлекаю слово, смещение и длину и помещаю все это в TtntStringList в такое примерно виде:

30 30 64 61 74 61 62 61 73 65 69 6E 66 6F=0|1313
30 30 64 61 74 61 62 61 73 65 73 63 72 69 70 74=1313|10413

до знака равно это закодированное слово, затем смещение и длина.
Осталось только декодировать само слово преобразовав его в читаемые символы не потеряв при этом юникода.


 
Anatoly Podgoretsky ©   (2008-06-14 00:31) [26]


> почему же, это может быть UTF8 - все что до 7F кодируется
> одним байтом.

Хотя бы из-за этого 00 00, а до него обычный ASCII
И больше никакой информации из файла не приведно, хотя и это достаточно, чтобы сказать, что это не UTF8



Страницы: 1 вся ветка

Текущий архив: 2008.07.13;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.018 c
2-1213333226
TForumHelp
2008-06-13 09:00
2008.07.13
Значение из TMyComponent


15-1212088289
Дмитрий С
2008-05-29 23:11
2008.07.13
Можно ли в Delphi использовать lib-файл?


15-1211809617
Альф
2008-05-26 17:46
2008.07.13
Инсталятор с возможностью тихой установки


2-1213285768
ivan8511
2008-06-12 19:49
2008.07.13
Индекс в обратном порядке


2-1213112909
Гошум
2008-06-10 19:48
2008.07.13
SetFileAttributes