为什么我的Luhn校验和在Windows上正确计算但在Android上没有计算?

时间:2015-03-03 18:50:20

标签: android delphi

我在Internet上获得此Luhn函数,当我为Windows32 VCL编译它时,它是正确的。但是当我编译它以在Android应用程序中使用时,我得到一个False而不是True,我怀疑这是因为它正在转换为utf8到期望ascii的字节转换。

那么,为了在Android上正常工作,我该怎么办?

function Luhn(Code: string): Boolean;
var
    i, sum: integer;
    temp: byte;
begin
{ calcula o algorítimo luhn, usado no iccid }
    sum := 0;
    for i:= length(Code) downto 1 do
    begin  // Run the characters backwards
      temp := byte(Code[i])-48;             // Convert from ASCII to byte
      if (length(Code)-i) mod 2 = 0
        then sum := sum + temp             // Odd characters just add
        else if temp < 5
           then sum := sum + 2*temp        // Even characters add double
           else sum := sum + (2*temp)-9;   // or sum the digits of the doubling
    end;
    Result := sum mod 10 = 0;              // Return true if sum ends in a 0
    if Result then
      Toast(Code+#13+'True')
    else
      Toast(Code+#13+'False');

end;

2 个答案:

答案 0 :(得分:6)

像大卫说的那样,这个问题与桌面和移动编译器默认不同地索引字符串这一事实有关。字符串在桌面编译器中仍然是1索引的,但在移动编译器中默认为0索引。这在文档中描述:

Migrating Delphi Code to Mobile from Desktop | Use 0-Based Strings

要使代码以您不必处理ZBS差异的方式工作,您可以:

  1. 使用{$ZEROBASEDSTRINGS OFF}返回移动设备上基于1的索引

    {$IFDEF NEXTGEN}
      {$ZEROBASEDSTRINGS OFF}
    {$ENDIF}
    
    function Luhn(Code: string): Boolean;
    var
      i, sum: integer;
      temp: byte;
    begin
      { calcula o algorítimo luhn, usado no iccid }
      sum := 0;
      for i := Length(Code) downto 1 do begin  // Run the characters backwards
        temp := byte(Ord(Code[i]))-48;  // Convert from ASCII to byte
        if (Length(Code)-i) mod 2 = 0 then
          sum := sum + temp             // Odd characters just add
        else if temp < 5 then
          sum := sum + (2*temp)         // Even characters add double
        else
          sum := sum + (2*temp) - 9;    // or sum the digits of the doubling
      end;
      Result := sum mod 10 = 0;         // Return true if sum ends in a 0
      if Result then
        Toast(Code+#13+'True')
      else
        Toast(Code+#13+'False');
    end;
    
    {$IFDEF NEXTGEN}
      {$ZEROBASEDSTRINGS ON}
    {$ENDIF}
    
  2. 使用Low(String)High(String)系统函数:

    function Luhn(Code: string): Boolean;
    var
      i, sum: integer;
      temp: byte;
    begin
      { calcula o algorítimo luhn, usado no iccid }
      sum := 0;
      for i := High(Code) downto Low(Code) do begin  // Run the characters backwards
        temp := byte(Ord(Code[i]))-48;  // Convert from ASCII to byte
        if (High(Code)-i) mod 2 = 0 then
          sum := sum + temp             // Odd characters just add
        else if temp < 5 then
          sum := sum + (2*temp)         // Even characters add double
        else
          sum := sum + (2*temp) - 9;    // or sum the digits of the doubling
      end;
      Result := sum mod 10 = 0;         // Return true if sum ends in a 0
      if Result then
        Toast(Code+#13+'True')
      else
        Toast(Code+#13+'False');
    end;
    
  3. 使用TStringHelper助手类:

    uses
      ..., SysUtils;
    
    function Luhn(Code: string): Boolean;
    var
      i, sum: integer;
      temp: byte;
    begin
      { calcula o algorítimo luhn, usado no iccid }
      sum := 0;
      for i := Code.Length-1 downto 0 do begin  // Run the characters backwards
        temp := byte(Ord(Code.Chars[i]))-48;  // Convert from ASCII to byte
        if (Code.Length-1-i) mod 2 = 0 then
          sum := sum + temp             // Odd characters just add
        else if temp < 5 then
          sum := sum + (2*temp)         // Even characters add double
        else
          sum := sum + (2*temp) - 9;    // or sum the digits of the doubling
      end;
      Result := sum mod 10 = 0;         // Return true if sum ends in a 0
      if Result then
        Toast(Code+#13+'True')
      else
        Toast(Code+#13+'False');
    end;
    

答案 1 :(得分:5)

问题是,默认情况下,字符串为零,基于移动编译器,但默认情况下基于桌面编译器。您需要调整代码以解决此问题。变化

Code[i]

Code[i-1]

我建议使用

{$ZEROBASEDSTRINGS ON}

如果您希望在移动和桌面目标之间共享代码。详情请见http://docwiki.embarcadero.com/RADStudio/en/Zero-based_strings_(Delphi)


一些旁白:

  • 这里根本没有UTF-8。
  • 代码非常脆弱,代码点超出ASCII范围会很糟糕。一些健全检查是谨慎的。
  • 我建议使用ord()从字符中获取序数值。
  • 您可能会考虑使用内在odd()函数而不是显式mod测试。

所以,我个人会写这样的代码:

function LuhnChecksumValid(const Value: string): Boolean;
var
  C: Char;
  Digit: Integer;
  Sum: Integer;
  OddChar: Boolean;
begin
  if Value.Length=0 then
    Exit(False);

  Sum := 0;
  OddChar := odd(Value.Length);
  for C in Value do
  begin
    Digit := ord(C) - ord('0');
    if not InRange(Digit, 0, 9) then
      Exit(False);
    if OddChar then
      inc(Sum, Digit)
    else if Digit < 5 then
      inc(Sum, 2*Digit)
    else
      inc(Sum, 2*Digit - 9);
    OddChar := not OddChar;
  end;
  Exit((9*Sum) mod 10 = 0);
end;

请注意,我故意避免使用索引。这样做可以让我们完全支持零基或一基指数的问题。