
Números gigantes a Hexadecimal y visceversa
#1
Escrito 30 agosto 2011 - 04:42
#2
Escrito 30 agosto 2011 - 04:57
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} function StrToHex(s : string) : LongWord; var bb : Byte; cc : Char; begin Result := 0; s := UpperCase(s); for bb := 1 to Length(s) do begin Result := Result * 16; cc := s[bb]; case cc of '0'..'9': Inc(Result, ord(cc) - ord('0')); 'A'..'F': Inc(Result, ord(cc) - ord('A')+10); else raise EConvertError.Create('Tu error'); end; end; end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(IntToStr(StrToHex('BBA1'))); // 48033 end; end.
#3
Escrito 30 agosto 2011 - 07:45
function StringToGUID(S: String): TGUID; var i: integer; begin Result.Data1:= StrToInt('$'+Copy(S, 2, 8)); Result.Data2:= StrToInt('$'+Copy(S, 11, 4)); Result.Data3:= StrToInt('$'+Copy(S, 16, 4)); for i:=0 to 1 do Result.Data4[i]:= BYTE(StrToInt('$'+Copy(S, 21+i*2, 2))); for i:=2 to 7 do Result.Data4:= BYTE(StrToInt('$'+Copy(S, 22+i*2, 2))); end; function GUIDToString(guid: TGUID): String; var i: integer; begin Result:= '{' + IntToHex(guid.Data1, 4) + '-' + IntToHex(guid.Data2, 2) + '-' + IntToHex(guid.Data3, 2) + '-'; for i:=0 to 1 do Result:= Result + IntToHex(guid.Data4, 2); Result:= Result + '-'; for i:=2 to 7 do Result:= Result + IntToHex(guid.Data4, 2); Result:= Result + '}'; end;
Ejemplo de uso:
var G: TGUID; S: String; begin G:= StringToGUID('{2A8DEC8D-934E-4FF8-825A-05A800047649}'); S:= GUIDToString(G); end;
No incorpora comprobación de errores, pero si entiendes el código no te será difícil incorporarla.
Saludos.
#4
Escrito 31 agosto 2011 - 07:56

¡Lazarus tiene las dos funciones que propuse arriba y con el mismísimo nombre!:
StringToGUID
GUIDToString
PD. Código fuente en sysuintf.inc
Saludos.
#5
Escrito 31 agosto 2011 - 09:25
#6
Escrito 31 agosto 2011 - 09:46
¿Ese entero "autentico" lo necesitas para algo? ¿No te valdria igual un string que hiciese la misma funcion de almacenar ese GUI?
#7
Escrito 31 agosto 2011 - 09:53
#8
Escrito 31 agosto 2011 - 10:11
Lazarus define TGuid como:
TGuid = packed record case integer of 1 : ( Data1 : DWord; Data2 : word; Data3 : word; Data4 : array[0..7] of byte; ); 2 : ( D1 : DWord; D2 : word; D3 : word; D4 : array[0..7] of byte; ); 3 : ( { uuid fields according to RFC4122 } time_low : dword; // The low field of the timestamp time_mid : word; // The middle field of the timestamp time_hi_and_version : word; // The high field of the timestamp multiplexed with the version number clock_seq_hi_and_reserved : byte; // The high field of the clock sequence multiplexed with the variant clock_seq_low : byte; // The low field of the clock sequence node : array[0..5] of byte; // The spatially unique node identifier ); end;
¿Por qué no usar el tipo ya previsto?. Esa fue la razón de mi respuesta...
Y ahora me pregunto: ¿Por qué no te sirve?
Saludos.
#9
Escrito 31 agosto 2011 - 10:19
#10
Escrito 31 agosto 2011 - 10:38
Pero viendo para lo que lo quieres usar, quizas seria mejor usar una funcion de hash sobre el GUID en modo string, por ejemplo MD5 o SHA1, eso te daria otro string "mezclando todo", ahora recortarias las primeras 6 o 7 letras, la conviertes de array of word (los char individuales) a int (el int del primero, *256, mas el int del segundo, *256, etc) y al final lo que consigues es acortar la longitud del numero resultante (a mas cifras, uses del hash, mayor numero obtienes, claro, no se si los 6 o 7 que te proponia seran demasiados o no) sin que deje de ser unico... bueno, en teoria podria repetirse un entero, pero la probabilidad es del orden de 1/10^12 (al ser numeros de 12 cifras), es decir, un 0.0000000001% de que dos GUID se repitan y "choquen", bastante asumible... sobre todo porque usando numeric(12,0) no puedes aspirar a más!
#11
Escrito 31 agosto 2011 - 10:53
#12
Escrito 31 agosto 2011 - 09:54
A mi entender, y advierto que con poca experiencia, sobre GUID lo mejor, rápido y sencillo es cortar por lo simple: almacenar eso como string.
O cuanto mucho, definir varios campos que almacenen cada grupo y trabajar con ellos en forma individual y "unirnos" en cuanto se requiera.
Sergio no me parece muy adecuada la idea de utilizar MD5... ten en cuenta que es un algoritmo irreversible. Y el punto es que se requiere poder recuperar el valor.
Ahora yo tengo una pregunta... ¿Y por casualidad Oracle no dispone de funciones, etc para operar con esto? Yo creeía que si.
Saludos,
#13
Escrito 01 septiembre 2011 - 09:50
#14
Escrito 02 septiembre 2011 - 02:36
Sin aclarar antes este punto no hay mucho que hacer.
#15
Escrito 10 septiembre 2011 - 03:29
Hola a todos, no había podido dar repuesta por tanto trabajo, pero les cuento:
un hexadecimal EBD0A0A2B9E5443387C068B6B72699C7 lo convierto a decimal 313451834834061278758346828331453159879 así
[DELPHI]{Convierte un hexadecimal en un TBCD}
Function HexToBCD(s : string) : TBcd;
var
bb : Byte;
cc : Char;
begin
Result := 0;
s := UpperCase(s);
for bb := 1 to Length(s) do
begin
Result := Result * 16;
cc := s[bb];
case cc of
'0'..'9': Result:= Result + ord(cc) - ord('0');
'A'..'F': Result:= Result + ord(cc) - ord('A')+10;
else raise EConvertError.Create('Se ha encontrado un caráctar no valido.');
end;
end;
end;[/DELPHI]
y desde el hexadecimal lo paso a binario 11101011110100001010000010100010101110011110010101000100001100111000011111000000011010001011011010110111001001101001100111000111 así
[DELPHI] {Convierte un hexadecimal en un binario}
Function HexToBin(Hexadecimal:string):string;
const
BCD: array [0..15] of string=
('0000','0001','0010','0011','0100','0101','0110','0111',
'1000','1001','1010','1011','1100','1101','1110','1111');
var
i:integer;
begin
for i:=Length(Hexadecimal) downto 1 do
Result:=BCD[StrToInt('$'+Hexadecimal)]+Result;
end;[/DELPHI]
desde el binario lo puedo pasar al hexadecimal así
[DELPHI]{Convierte un binario a hexadecimal}
function BinToHex(Binario:string):string;
const
BCD: array [0..15] of string=
('0000','0001','0010','0011','0100','0101','0110','0111',
'1000','1001','1010','1011','1100','1101','1110','1111');
HEX: array [0..15] of char=
('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
i,n:integer;
sTemp:string;
sNibble:string;
begin
Result:='';
sTemp:=Binario+Copy('000',1,Length(Binario) mod 4);
for i:=0 to (Length(Binario) shr 2)-1 do
begin
sNibble:=Copy(sTemp,(i shl 2)+1,4);
n:=8;
while (sNibble <> BCD[n]) do
if sNibble < BCD[n] then Dec(n) else Inc(n);
Result:=Result+HEX[n];
end;
end;
[/DELPHI]
El gran problema es que desde el décimal no he podido pasarlo a hexadecimal, alguna idea?
#16
Escrito 12 septiembre 2011 - 02:48
function Dec2Hex(decimal: LongInt): string; const Hex: array [0..15] of string = ('0', '1', '2','3','4','5','6','7','8','9','A','B','C','D','E','F'); begin result:= ''; while decimal>0 do begin Digito:= decimal mod 16; decimal:= decimal div 16; result:= result + Hex[Digito]; end; end;
Esta es la base matematica, hacer divisiones por 16 y quedarse con el resto para saber el proximo digito en hexadecimal, y la division entera para continuar extrayendo digitos... pero si "decimal" es una cadena, el reproducir esto sin usar enteros muy largos es mucho mas dificil que en las otras conversiones que ya tienes... pero bueno, se podria hacer, necesitarias una funcion que dado un decimal en string te devuelva el resto de dividir por 16 y el resultado entero de esa division, y llamarlo dentro del while de arriba.
Lo que pasa es que muy tedioso: Primero, has de ir restandole 16 al decimal -que es un string- hasta que te quede algo menor de 16, ese algo es el resto, el proximo digito hexadecimal, mas luego has de llevar la cuenta de cuantas veces le restas 16, porque ese sera el numevo "decimal" para el siguiente digito.
Claro, visto asi no aparenta excesivamente dificil, pero ojo, el nuevo "decimal", esa cuenta de veces que le restamos 16, no te va a caber en un LongInt, asi que has de llevar esa cuenta de nuevo en un string, y sumarle 1 a un entero en un string pues tambien tienes que programarlo, asi que necesitas dos rutinas nuevas:
procedure Div16(entero: string; var resto: integer; var resultado: string); begin resultado:= '0'; //Detecto cuando he terminado de restar 16.... //Como el segundo 'or' no se calcula si el primero da true, no desbordare el StrToInt() while (Length(entero)>2) or (StrToInt(entero)>15) do begin entero:= Quitar16(entero); resultado:= Sumar1(resultado); end; resto:= StrToInt(entero); end;
Y ahora te faltarian las otras dos: Quitar16(numero: string): string; y Sumar1(numero: string): string;
Una vez que te he soltado todo este rollo, mi consejo es que para esto uses rutinas de precision arbitraria, la que te comente al principio, lo que consigues es poder usar el while primero sin tener que acudir hacer calculos con numeros dentro de strings, que es un verdadero follón, lento y delicado de hacer... y ya está hecho en estas rutinas!
Por cierto, estas rutinas hacen lo mismo pero con arrays dinamicos de digitos y cosas asi, no es tan diferente a lo que te cuento, pero se busca eficiencia (no quedarse sin memoria) y velocidad (poder hacer cosas "serias" con precisión arbitraria).
#17
Escrito 14 septiembre 2011 - 07:35
[/color][/size]
[font=monospace][size=13px][color=gray][color=rgb(0, 0, 0)][font=Verdana][/font][/color][/size][/font] {Convierte un TBCD en un hexadecimal} function BCDToHex(BCD: TBCD): string; const B16: array[0..15] of Char = ('0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F'); var BcdEx,DivBcd: TBCD; ModInt,SepDec: Integer; begin Result:= ''; while (Bcd > 0) do begin BCDDivide(Bcd,16,BcdEx); SepDec:=Pos(DecimalSeparator,BCDToStr(BcdEx))-1; If SepDec > 0 then begin DivBcd:=StrToBCD(Copy(BCDToStr(BcdEx),0,SepDec)); end else begin DivBcd:=BcdEx; End; ModInt:=StrToInt(BCDToStr(Bcd - (16 * DivBcd))); Result:= B16[ModInt] + Result; BCD:=DivBCD; end; end;
también les dejo un proyecto de ejemplo, gracias nueva mente =)