Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   ANSI, UNICODE, Big Endian y UTF-8 (https://www.clubdelphi.com/foros/showthread.php?t=35449)

ixMike 11-09-2006 19:45:08

ANSI, UNICODE, Big Endian y UTF-8
 
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:

Código Delphi [-]
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

Código Delphi [-]
 
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 21:00:02

Personalmente la segunda función la haría de la siguiente manera:

Código Delphi [-]
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 21:08:28

Un buen articulo:

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

seoane 11-09-2006 21: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 12:58:55

Cita:

Empezado por seoane
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 12: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:

Código Delphi [-]
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:

Código Delphi [-]
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 13:53:42

Cita:

Empezado por ixMike
seoane, la función que hiciste tiene un pequeño fallo

:confused: ¿que fallo?

Esto:
Código Delphi [-]
  WStr:=' '+Text;
  WStr[1]:=WideChar($FEFF);

Es lo mismo que esto:
Código Delphi [-]
  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:
Código Delphi [-]
  WStr:= #$FEFF + WideString(Text);

ContraVeneno 15-08-2007 20:40:52

Gracias ixMike
este hilo me ha servido de maravillas :D

Muchas gracias


La franja horaria es GMT +2. Ahora son las 18:18:13.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi