Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

There is an ansi version of StrToInt?

Tags:

delphi

It seems there is no Ansi overload for StrToInt. Is this right? Or maybe I am missing something. StrToInt insists to convert my ansistrings to string.

like image 277
Server Overflow Avatar asked Jun 16 '14 13:06

Server Overflow


2 Answers

You are correct. There is no ANSI version of StrToInt. The place to find ANSI versions of standard function is the AnsiStrings unit, and there's nothing there.

Either write your own function to do the job, or accept the conversion required to use StrToInt.

It's not too hard to write your own function. It might look like this:

uses 
  SysConst; // for SInvalidInteger
....
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
function AnsiStrToInt(const s: AnsiString): Integer;

  procedure Error;
  begin
    raise EConvertError.CreateResFmt(@SInvalidInteger, [s]);
  end;

var
  Index, Len, Digit: Integer;
  Negative: Boolean;
begin
  Index := 1;
  Result := 0;
  Negative := False;
  Len := Length(s);
  while (Index <= Len) and (s[Index] = ' ') do
    inc(Index);
  if Index > Len then
    Error;
  case s[Index] of
  '-','+':
    begin
      Negative := s[Index] = '-';
      inc(Index);
      if Index > Len then
        Error;
    end;
  end;
  while Index <= Len do
  begin
    Digit := ord(s[Index]) - ord('0');
    if (Digit < 0) or (Digit > 9) then
      Error;
    Result := Result * 10 + Digit;
    if Result < 0 then
      Error;
    inc(Index);
  end;
  if Negative then
    Result := -Result;
end;

This is a cut-down version of that found in StrToInt. It does not handle hexadecimal and is a bit more stringent regarding errors. Before using this code I'd want to test whether or not this really is your bottleneck.

It is quite interesting that this code, based on that in the RTL source, is incapable of returning low(Integer). It's not too hard to fix that up, but it would make the code more complex.

like image 91
David Heffernan Avatar answered Sep 28 '22 16:09

David Heffernan


The code is actually very simple (hex strings aren't supported but prolly you don't need them):

function AnsiStrToInt(const S: RawByteString): Integer;
var
  P: PByte;
  Negative: Boolean;
  Digit: Integer;

begin
  P:= Pointer(S);
// skip leading spaces
  while (P^ = Ord(' ')) do Inc(P);
  Negative:= False;
  if (P^ = Ord('-')) then begin
    Negative:= True;
    Inc(P);
  end
  else if (P^ = Ord('+')) then Inc(P);

  if P^ = 0 then
    raise Exception.Create('No data');

  Result:= 0;
  repeat
    if Cardinal(Result) > Cardinal(High(Result) div 10) then
      raise Exception.Create('Integer overflow');
    Digit:= P^ - Ord('0');
    if (Digit < 0) or (Digit > 9) then
      raise Exception.Create('Invalid char');
    Result:= Result * 10 + Digit;
    if (Result < 0) then begin
      if not Negative or (Cardinal(Result) <> Cardinal(Low(Result))) then
        raise Exception.Create('Integer overflow');
    end;
    Inc(P);
  until (P^ = 0);
  if Negative then Result:= -Result;
end;
like image 42
kludg Avatar answered Sep 28 '22 14:09

kludg