Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.07.13;
Скачать: [xml.tar.bz2];

Вниз

Чтение данных из файла 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.007 c
3-1201857058
Son_of_Morning
2008-02-01 12:10
2008.07.13
Помогите определится с выбором СУБД


15-1211885033
pasha_golub
2008-05-27 14:43
2008.07.13
Превратить старый ноутбук в multimedia комбайн


2-1213367274
DJ_UZer
2008-06-13 18:27
2008.07.13
Правильное открытие в браузере


2-1213532252
WebSQLNeederrr
2008-06-15 16:17
2008.07.13
Как узнать количество картинок в документе TWebBrowser?


2-1213167659
deras
2008-06-11 11:00
2008.07.13
Как обнулить счетчик генератора в FireBird?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский