将Int64转换为Base30和Back

时间:2010-08-12 19:40:36

标签: delphi

对于注册码,我想将Int64转换为base30(30只使用大写字符,不包括0,O,I,1等)并返回。

使用以下功能并不太难:

const
  Base = 30;
  Base30CharSet = '23456789ABCDEFGHJKLMNPRSTVWXYZ';

function ConvertIntToBase30(ANumber: Int64): string;
begin
  if(ANumber = 0) then
    Result := Copy(Base30CharSet, 1, 1)
  else begin
    Result := '';
    while(ANumber <> 0) do begin
      Result := Copy(Base30CharSet, (ANumber mod Base)+1, 1) + Result;
      ANumber := ANumber div Base;
    end;
  end;
end;

function ConvertBase30ToInt(ANumber: string): Int64;
var
  i: integer;
begin
  Result := 0;
  for i := 1 to Length(ANumber) do begin
    Result := Result + (Pos(ANumber[i], Base30CharSet)-1);
    if(i < Length(ANumber)) then
      Result := Result * Base;
  end;
end;

问题在于我对Int64的感兴趣,所以我可以处理像$FFFFFFFFFFFFFFFF = -1这样的数字。

为了解决这个问题,我想我会存储并删除符号(abs())并将符号作为附加到base30结果的额外字符包含在内。 Int64下限发生的问题是调用abs(-9223372036854775808)导致溢出。

有没有人有解决方案或更好的算法来解决这个问题?

3 个答案:

答案 0 :(得分:1)

处理它的方法是让一个字符表示它是一个负数,这样你就可以解码了。对于负数,只需将位从1翻转为0并在编码前删除符号位,在解码时,执行回翻并添加符号位。以下是工作代码

   function InvertIntOff(const ANumberL, ANumberH: Integer): Int64;
    asm
      XOR EAX,$FFFFFFFF
      XOR EDX,$FFFFFFFF
    end;


function InvertIntOn(const ANumberL, ANumberH: Integer): Int64;
asm
  XOR EAX,$FFFFFFFF
  XOR EDX,$FFFFFFFF
  OR  EDX,$80000000
end;

function ConvertIntToBase(ANumber: Int64): string;
const
  CBaseMap: array[0..31] of Char = (
    '2','3','4','5','6','7','8','9', //0-7
    'A','B','C','D','E','F','G','H', //8-15
    'J','K','L','M','N', //16-20
    'P','Q','R','S','T','U','V','X','W','Y','Z'); //21-31
var
  I: Integer;
begin
  SetLength(Result, 15);
  I := 0;

  if ANumber < 0 then
  begin
    Inc(I);
    Result[I] := '1';
    ANumber := InvertIntOff(ANumber and $FFFFFFFF, (ANumber and $FFFFFFFF00000000) shr 32);
  end;

  while ANumber <> 0 do
  begin
    Inc(I);
    Result[I] := CBaseMap[ANumber and $1F];
    ANumber := ANumber shr 5;
  end;

  SetLength(Result, I);
end;

function ConvertBaseToInt(const ABase: string): Int64;
var
  I, Index: Integer;
  N: Int64;
begin
  Result := 0;
  if Length(ABase) > 0 then
  begin
    if ABase[1] = '1' then
      Index := 2
    else
      Index := 1;
    for I := Index to Length(ABase) do
    begin
      case ABase[I] of
        '2'..'9':
          N := Ord(ABase[I]) - Ord('2');
        'A'..'H':
          N := Ord(ABase[I]) - Ord('A') + 8;
        'J'..'N':
          N := Ord(ABase[I]) - Ord('J') + 16;
        'P'..'Z':
          N := Ord(ABase[I]) - Ord('P') + 21;
        else
          raise Exception.Create('error');
      end;
      if I > Index then
        Result := Result or (N shl ((I - Index) * 5))
      else
        Result := N;
    end;

    if ABase[1] = '1' then
      Result := InvertIntOn(Result and $FFFFFFFF, (Result and $FFFFFFFF00000000) shr 32);
  end;
end;

procedure TestBase32;
var
  S: string;
begin
  S := ConvertIntToBase(-1);
  ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -1');

  S := ConvertIntToBase(-31);
  ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -31');

  S := ConvertIntToBase(1);
  ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? 1');

  S := ConvertIntToBase(123456789);
  ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? 123456789');

  S := ConvertIntToBase(-123456789);
  ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -123456789');
end;

答案 1 :(得分:0)

我认为你几乎在考虑abs()......

但是为什么不简单地忽略用于处理Int64本身值的符号,而不是使用abs()?据我所知,你实际上已经这样做了,所以编码例程只需要一个小的补充:

  if aNumber < 0 then
    // negative
  else
    // positive;

唯一的问题是生成的Base30字符串中的符号信息丢失。因此,使用从 aNumber&lt;中获得的新信息将其视为要解决的单独问题。 0 测试...

我发现你排除了所有可能混淆为0或1的字符,但也排除了0和1。因此,您可以使用0和1表示正面或负面(反之亦然)。

根据这些例程的目的,在结果中放置0/1可能完全是任意的(如果你希望混淆事物并使0/1随机放置而不是一致的前导/跟踪字符)。

当编码时,只需将符号指示符随机地放入结果字符串中,并在解码时处理0/1字符,只要遇到符号标记,但为了解码该值而跳过。

当然,如果混淆不是问题,那么只需要一致地预先或后固定标志指示。

你甚至可以简单地选择使用'1'来表示负数,并使用'1'的LACK来表示/假设为正(这会简化我认为的零值情况)

答案 2 :(得分:0)

简单的答案是关闭范围检查,即使只是你正在调用abs的方法。

如果你不关心额外的一两个字符,你可以将int64分成单词或双字并将它们串在一起。我更想尝试使用base32并使用位移来提高速度和易用性。然后您的编码变为

Base32CharSet [(ANumber shr 5)%32]

和类似的基于pos()的解码方法。