PDA

Ver la Versión Completa : ANSI, UNICODE, Big Endian y UTF-8


ixMike
11-09-2006, 18:45:08
Hola, amigos,

El otro día estaba intentando hacer un código para extraer el texto de un archivo UNICODE y ponerlo en un TMemo (por ejemplo). Usé los archivos de C:\WINDOWS\inf para probar. El resultado fue exitoso, pero surgieron nuevas dudas:

Diferencia entre UNICODE, UNICODE Big Endian y UTF-8

Además, intenté hacer una función inverse (guardar el texto de un TMemo en un archivo UNICODE). La función está casi hecha, pero tiene un fallo. Aquí estan las dos:

DE ARCHIVO UNICODE A TEXTO ANSI:


Function UnicodeToAnsi(FileName: String): String;

type //Bloque de lectura de 256 KB
TBloque = array [0..131071] of WideChar;

var
F : File of TBloque;
F2: File of WideChar;
C : TBloque;
C2: WideChar;
P : PWideChar;
Max, Posi, N: Integer;
Fin, S: String;

begin
//Inicializar
Result:='';
S:='';
Fin:='';
Max:=0;
Pos:=0;

//Comprobaciones
If not FileExists(FileName) then
begin
raise Exception.Create('El archivo indicado no existe');
exit;
end;

//Calcular tamaño máximo
AssignFile(F2, FileName);
Reset(F2);
Max:=FileSize(F2);
CloseFile(F2);

//Si el archivo está vacío, salimos
If Max=0 then exit;

//Leer grandes bloques
AssignFile(F, FileName);
Reset(F);
If FileSize(F)>0 then
for n:=1 to FileSize(F) do
begin
Seek(F, n-1);
Read(F, C);
P:=C;
WideCharToStrVar(P, S);
Fin:=Fin+S;
Fin:=Copy(Fin, 1, Length(Fin)-1);
end;
Posi:=FileSize(F)*131072;
CloseFile(F);

//Si con los bloques lo hemos leído todo
if Posi=Max then
begin
Result:=Copy(Fin, 2, Length(Fin)-1);
Exit;
end;

//Si quedan datos por leer
AssignFile(F2, FileName);
Reset(F2);
for n:=Posi to Max-1 do
begin
Seek(F2, n);
Read(F2, C2);
S:=C2;
Fin:=Fin+S;
end;

CloseFile(F2);

//Damos el resultado final
Result:=Copy(Fin, 2, Length(Fin)-1);
end;



GUARDAR TEXTO ANSI EN ARCHIVO UNICODE



Procedure AnsiToUnicode(Text, FileName: String);

type
TBloq = array[0..8191]of WideChar;

var
F : File of TBloq;
F2: File of WideChar;
B : TBloq;
W : WideChar;
S : String;
Max, Posi, N: Integer;

begin
//Inicializar
Posi:=0;
Max:=Length(Text);
If Max=0 then Exit; //Salimos si no hay texto

//Empezamos a escribir el archivo
AssignFile(F,FileName);
ReWrite(F);

//Si podemos usar los bloques
If Max>8191 then for N:=1 to Max div 8192 do
begin
If N=0 then
begin
S:='_'+Copy(Text,1,8191);
StringToWideChar(S,@B,8192);
B[0]:=WideChar($FEFF);
Write(F,B);
Inc(Posi,8192);
end
else
begin
S:=Copy(Text,(N-1)*8191+1,8192);
StringToWideChar(S,@B,8192);
Write(F,B);
Inc(Posi,8192);
end;
end;

//Si ya hemos acabado cerramos el archivo
if Posi=Max then
begin
CloseFile(F);
Exit;
end;

//Si no hemos acabo, seguimos
CloseFile(F);
AssignFile(F2,FileName);
Reset(F2);
Seek(F2,FileSize(F2));
If Posi=0 then
begin
W:=WideChar($FEFF);
Write(F2,W);
end;
For N:=Posi to Max do
begin
W:=WideChar(Text[n]);
Write(F2,W);
end;

//Finalizamos
CloseFile(F2);
end;




¿Alguien podría ayudarme a acabar la segunda función?
¿Alguien podría explicarme la diferencia entre UNICODE, Big Endian y UTF-8, y cómo cargar estos archivos en un TMemo?

Muchísimas gracias.

seoane
11-09-2006, 20:00:02
Personalmente la segunda función la haría de la siguiente manera:


procedure AnsiToUnicode(Text, Filename: string);
var
WStr: WideString;
F: File;
Escritos: Integer;
begin
WStr:= #$FEFF + Text;
AssignFile(F, Filename);
{$I-}
Rewrite(F,Sizeof(WideChar));
{$I+}
if IOResult = 0 then
begin
BlockWrite(F,PWChar(WStr)^,Length(WStr),Escritos);
CloseFile(F);
end;
end;


En cuanto a tu función, ¿cual es exactamente el fallo que te da?

mamcx
11-09-2006, 20:08:28
Un buen articulo:

http://www.joelonsoftware.com/articles/Unicode.html

seoane
11-09-2006, 20:46:03
Voy a contar una anécdota por si a alguien le puede ser de utilidad. Hace unos días un amigo intentaba enviar una cadena de texto a un teléfono móvil a través del bluetooth, este texto lo leía después en el móvil con un applet hecho en java. Para ello, inocentemente, usaba la instrucción ReadUTF de java. Pero algo fallaba, resulta que java tiene su propio formato para las cadenas UTF, hay que añadir al principio de cada cadena 2 bytes (el byte alto primero) que representan el tamaño en bytes de la cadena.

ixMike
13-09-2006, 11:58:55
En cuanto a tu función, ¿cual es exactamente el fallo que te da?

Pues sencillamente aparece un byte (que no debería estar) en la tercera posición. Creo que es debido a eso que dices del ReadUTF del móvil.

Muchas gracias por la función (qué cortita, en comparación con la mía)

Y gracias mamcx por el artículo

ixMike
14-09-2006, 11:26:45
Gracias otra vez por el artículo, he aprendido mucho.

seoane, la función que hiciste tiene un pequeño fallo: aquí va la corrección:


procedure AnsiToUnicode(Text, Filename: string);
var
WStr: WideString;
F: File;
Escritos: Integer;
begin
WStr:=' '+Text;
WStr[1]:=WideChar($FEFF);
AssignFile(F, Filename);
{$I-}
Rewrite(F,Sizeof(WideChar));
{$I+}
if IOResult = 0 then
begin
BlockWrite(F,PWChar(WStr)^,Length(WStr),Escritos);
CloseFile(F);
end;
end;


También he mejorado la mía (la que extrae el texto del archivo UNICODE). Aquí va:


Function UnicodeToAnsi(FileName: String): string;
type
TAr = Array[0..0] of WideChar;
var
F: File;
WStr: WideString;
AStr: String;
Ar: ^Tar;
begin
Result:='';
If not FileExists(FileName) then exit;
AssignFile(F,FileName);
FileMode:=0;
Reset(F,1);
GetMem(Ar,FileSize(F));
BlockRead(F,Ar^,FileSize(F));
CloseFile(F);
WideCharToStrVar(PWideChar(Ar),AStr);
FreeMem(Ar);
Result:=Copy(AStr,2,Length(AStr)-1);
end;


Bueno, seguro que aún se puede mejorar.

Hasta otra ;)

seoane
14-09-2006, 12:53:42
seoane, la función que hiciste tiene un pequeño fallo


:confused: ¿que fallo?

Esto:

WStr:=' '+Text;
WStr[1]:=WideChar($FEFF);


Es lo mismo que esto:

WStr:= #$FEFF + Text;


No entiendo porque lo haces de la otra manera. Pero de ahí a decir que lo otro es un fallo :rolleyes:

EDITO: Parece que en versiones anteriores de delphi (yo usaba el TurboDelphi), la instrucción que pongo yo se le atraganta. Pero todo tiene solución:

WStr:= #$FEFF + WideString(Text);

ContraVeneno
15-08-2007, 19:40:52
Gracias ixMike
este hilo me ha servido de maravillas :D

Muchas gracias