Форум: "Начинающим";
Текущий архив: 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