开发者

How can I quickly convert an array of numeral characters into an integer?

Situation: a whole number saved as hex in a byte array(TBytes). Convert that number to type integer with less copying, if possible without any copying.

here's an example:

array = ($35, $36, $37);

This is '5', '6', '7' in ansi. How do I convert it to 567(=$273) with less trouble?

开发者_StackOverflow社区

I did it by copying twice. Is it possible to be done faster? How?


You can use LookUp Table instead HexToInt...

This procedure works only with AnsiChars and of course no error checking is provided!

var
  Table        :array[byte]of byte;

procedure InitLookupTable;
var
  n:            integer;
begin
  for n := 0 to Length(Table) do
    case n of
      ord('0')..ord('9'): Table[n] := n - ord('0');
      ord('A')..ord('F'): Table[n] := n - ord('A') + 10;
      ord('a')..ord('f'): Table[n] := n - ord('a') + 10;
    else Table[n] := 0;
    end;
end;

function HexToInt(var hex: TBytes): integer;
var
  n:            integer;
begin
  result := 0;
  for n := 0 to Length(hex) -1 do
    result := result shl 4 + Table[ord(hex[n])];
end;


function BytesToInt(const bytes: TBytes): integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to high(bytes) do
    result := (result shl 4) + HexToInt(bytes[i]);
end;

As PA pointed out, this will overflow with enough digits, of course. The implementation of HexToInt is left as an exercise to the reader, as is error handling.


You can do

function CharArrToInteger(const Arr: TBytes): integer;
var
  s: AnsiString;
begin
  SetLength(s, length(Arr));
  Move(Arr[0], s[1], length(s));
  result := StrToInt(s);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TBytes;
begin
  a := TBytes.Create($35, $36, $37);
  Caption := IntToStr(CharArrToInteger(a));
end;

If you know that the string is null-terminated, that is, if the final character in the array is 0, then you can just do

function CharArrToInteger(const Arr: TBytes): integer;
begin
  result := StrToInt(PAnsiChar(@Arr[0]));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TBytes;
begin
  a := TBytes.Create($35, $36, $37, 0);
  Caption := IntToStr(CharArrToInteger(a));
end;

The most natural approach, however, is to use an array of characters instead of an array of bytes! Then the compiler can do some tricks for you:

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TCharArray;
begin
  a := TCharArray.Create(#$35, #$36, #$37);
  Caption := IntToStr(StrToInt(string(a)));
end;


It cannot be any faster than that ;-)

function HexToInt(num:pointer; size:Cardinal): UInt64;
var i: integer;
    inp: Cardinal absolute num;
begin
  if(size > SizeOf(Result)) then Exit;
  result := 0;
  for i := 0 to size-1 do begin
    result := result shl 4;
    case(PByte(inp+i)^) of
      ord('0')..ord('9'): Inc(Result, PByte(inp+i)^ - ord('0'));
      ord('A')..ord('F'): Inc(Result, PByte(inp+i)^ - ord('A') + 10);
      ord('a')..ord('f'): Inc(Result, PByte(inp+i)^ - ord('a') + 10);
    end;
  end;
end;
function fHexToInt(b:TBytes): UInt64; inline;
begin
  Result:=HexToInt(@b[0], Length(b));
end;

...
b:TBytes = ($35, $36, $37);
HexToInt(@b[0], 3);
fHexToInt(b);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜