【问题标题】:how to convert hexa to dec using delphi and hex to octal?如何使用delphi将十六进制转换为十进制并将十六进制转换为八进制?
【发布时间】:2017-11-27 23:35:47
【问题描述】:
function HexToDec(Str: string): Integer;
var
i, M: Integer;
begin
Result:=0;
M:=1;
Str:=AnsiUpperCase(Str);
for i:=Length(Str) downto 1 do
begin
case Str[i] of
  '1'..'9': Result:=Result+(Ord(Str[i])-Ord('0'))*M;
  'A'..'F': Result:=Result+(Ord(Str[i])-Ord('A')+10)*M;
end;
M:=M shl 4;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Edit1.Text<>'' then
Label2.Caption:=IntToStr(HexToDec(Edit1.Text));
end;

如何在没有函数的情况下使用它,因为我想在另一行再次调用结果,那么十六进制到八进制呢?我必须从十六进制转换为十进制,然后再从十进制转换为八进制吗?

【问题讨论】:

    标签: delphi


    【解决方案1】:

    Delphi 已经可以做到这一点,因此您无需编写解析数字的函数。其实很简单:

    function HexToDec(const Str: string): Integer;
    begin
      if (Str <> '') and ((Str[1] = '-') or (Str[1] = '+')) then
        Result := StrToInt(Str[1] + '$' + Copy(Str, 2, MaxInt))
      else
        Result := StrToInt('$' + Str);
    end;
    

    请注意,它也可以处理负十六进制数字,或像 +$1234 这样的数字。

    如何在没有功能的情况下使用它,因为我想在另一行再次调用结果?

    如果您想重复使用该值,请将HexToDec 的结果分配给一个变量并在IntToStr 中使用它。


    FWIW,在您的函数中,无需调用AnsiUpperCase,因为无论如何所有十六进制数字都在 ASCII 范围内。一个更简单的UpperCase 也应该可以工作。

    【讨论】:

    • 有点令人沮丧的是他涉及堆分配。有没有可以避免这种情况的 RTL 函数?
    • @David:不是我能想到的 RTL 函数。但这真的很划算吗?
    • 在某些情况下可能很重要。通常我不同意。
    • 避免堆分配的唯一方法是改进 OP 函数的版本,即解析每个十六进制数字并进行移位和加法的函数。如果情况需要最高速度,我会写一个,否则我会使用ˋStrToIntˋ。
    • 我最近编写了自己的IntToStrFloatToStr 类型的方法来处理固定长度的字符数组。这是我的 YAML 发射代码。在创建充满数字的大文件时,这极大地提高了性能。遗憾的是 RTL 没有这些功能。
    【解决方案2】:

    我的第一条评论是,您没有使用函数将十六进制转换为十进制(尽管您将转换为十进制作为中间值),而是将十六进制转换为整数。然后 IntToStr 有效地将整数转换为以 10 为底。为了概括您想要的内容,我将创建两个函数 - strBaseToInt 和 IntToStrBase 其中 Base 意味着例如十六进制为 16,十进制为 10,八进制为 8 等,并假设十六进制采用 A=10 的约定,依此类推,但(可能)Z = 35,使最大基数可能为 36。

    我不处理 + 或 - 但可以轻松添加。

    在反向函数中,再次为简单起见,我省略了支持负值。

    编辑

    感谢 Rudy 的改进

    编辑 2 - 根据 cmets 添加了溢出测试

    function StrBaseToInt(const Str: string; const Base : integer): Integer;
    var
      i, iVal, iTest: Longword;
    begin
      if (Base > 36) or (Base < 2) then raise Exception.Create('Invalid Base');
      Result:=0;
      iTest := 0;
      for i:=1 to Length(Str) do
      begin
        case Str[i] of
          '0'..'9': iVal := (Ord(Str[i])-Ord('0'));
          'A'..'Z': iVal := (Ord(Str[i])-Ord('A')+10);
          'a'..'z': iVal := (Ord(Str[i])-Ord('a')+10);
          else raise Exception.Create( 'Illegal character found');
        end;
        if iVal < Base then
        begin
          Result:=Result * Base + iVal;
          if Result < iTest then  // overflow test!
          begin
            raise Exception.Create( 'Overflow occurred');
          end
          else
          begin
            iTest := Result;
          end;
        end
        else
        begin
          raise Exception.Create( 'Illegal character found');
        end;
      end;
    end;
    

    然后,例如,您的 HexToOct 函数将如下所示

    function HexToOct( Value : string ) : string;
    begin
      Result := IntToStrBase( StrBaseToInt( Value, 16), 8 );
    end;
    

    附加

    一般功能是

    function BaseToBase( const Value : string; const FromBase, ToBase : integer ) : string;
    begin
      Result := IntToStrBase( StrBaseToInt( Value, FromBase ),ToBase );
    end;
    

    【讨论】:

    • 如果您有任何基数的转换,那么为什么要停在基数 16?您的基数经过测试在 2..36 范围内,但您只能为基数 2..16 编码(最高 'F')。对于基数 12,'F' 将是非法的。你也应该检查一下,即数字
    • 对不起@RudyVelthuis - 错字。我评论说我没有检查非法字符,为了简单起见,但如果需要我可以添加它。
    • 好的。我认为,如果它真的能够正确处理所有事情,甚至是错误的数字,它将使该函数更加有用。我首先将字符转换为数字(0..base - 1),然后将其添加到结果中。哦,我在IntToStrBase 的while 之后插入了一个开始,请参阅编辑。
    • @RudyVelthuis 谢谢 - 用缺少的开头打败了我:-)。我只是检查验证,很快就会更新帖子。
    • @RonMaupin 最初作为 OP 指南的东西似乎已经演变成一个完整的实现!不过,就这样吧。
    猜你喜欢
    • 2011-08-21
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 2015-09-13
    • 2013-10-08
    • 2012-06-26
    相关资源
    最近更新 更多