2009-09-13 51 views
10

有很多验证Luhn校验和的实现,但很少用于生成它们。我遇到过this one然而,在我的测试中,它已经显示出错误,并且我不理解delta变量背后的逻辑。生成Luhn校验和

我做了这个功能,据说应该生成Luhn校验码,但由于某种原因,我还没有理解生成的校验和是无效的一半时间。

function Luhn($number, $iterations = 1) 
{ 
    while ($iterations-- >= 1) 
    { 
     $stack = 0; 
     $parity = strlen($number) % 2; 
     $number = str_split($number, 1); 

     foreach ($number as $key => $value) 
     { 
      if ($key % 2 == $parity) 
      { 
       $value *= 2; 

       if ($value > 9) 
       { 
        $value -= 9; 
       } 
      } 

      $stack += $value; 
     } 

     $stack = 10 - $stack % 10; 

     if ($stack == 10) 
     { 
      $stack = 0; 
     } 

     $number[] = $stack; 
    } 

    return implode('', $number); 
} 

一些例子:

Luhn(3); // 37, invalid 
Luhn(37); // 372, valid 
Luhn(372); // 3728, invalid 
Luhn(3728); // 37283, valid 
Luhn(37283); // 372837, invalid 
Luhn(372837); // 3728375, valid 

我验证生成的校验against this page,我究竟做错了什么?


为了将来的参考,这里是工作函数。

function Luhn($number, $iterations = 1) 
{ 
    while ($iterations-- >= 1) 
    { 
     $stack = 0; 
     $number = str_split(strrev($number), 1); 

     foreach ($number as $key => $value) 
     { 
      if ($key % 2 == 0) 
      { 
       $value = array_sum(str_split($value * 2, 1)); 
      } 

      $stack += $value; 
     } 

     $stack %= 10; 

     if ($stack != 0) 
     { 
      $stack -= 10; 
     } 

     $number = implode('', array_reverse($number)) . abs($stack); 
    } 

    return $number; 
} 

我放弃了$奇偶性变量,因为我们并不需要它用于此目的,并核实:

function Luhn_Verify($number, $iterations = 1) 
{ 
    $result = substr($number, 0, - $iterations); 

    if (Luhn($result, $iterations) == $number) 
    { 
     return $result; 
    } 

    return false; 
} 
+2

顺便说一下,验证校验和与生成校验和是否相同,并检查它是否为零 - 因此所有这些'验证'例程也可用于生成。 – 2009-09-14 08:05:18

+0

@尼克:是的,但涉及检查10个不同的数字,我更喜欢反过来(使用生成函数验证)。 – 2009-09-14 11:59:22

+0

什么?不,您只需'追加'确认'数字,然后用(9结果)替换最后一位数字。 – 2009-09-14 14:06:53

回答

8

编辑:对不起,我现在认识到,你有我的差不多已经完整的答案,你刚刚错误地确定了哪个数字使用哪个因子。

我完整的答案,现在可以用这个简单的句子来概括:

你有逆转的因素,你被2取决于数量的长度乘以错误的数字。


看看Wikipedia article on the Luhn algorithm

您的校验和一半时间无效的原因是您的支票只有一半的时间您的号码有奇数的数字,然后您错误的数字翻倍。

为37283,从右边计数时,你得到的数字序列:

3 * 1 = 3    3 
    8 * 2 = 16 --> 1 + 6 = 7 
    2 * 1 = 2    2 
    7 * 2 = 14 --> 1 + 4 = 5 
+ 3 * 1 = 3    3 
=      20 

该算法要求您从原来的号码总结个人数字,以及那些产品的单个数字“每两位数字”。

所以从右侧,你总结3 +(1 + 6)+ 2 +(1 + 4)+ 3,它给你20.

如果结束与末端具有零的数目,哪20个,这个数字是有效的。

现在,您的问题暗示想知道如何生成的校验和,那么,这很容易,做到以下几点:

  1. 钉在一个零,所以你的电话号码从xyxyxyxy去xyxyxyxy0
  2. 计算LUHN校验和新数
  3. 采取的总和,模数10,所以你从0个位数至10
  4. 如果数字是0,那么恭喜你,你的校验位是零
  5. 否则,计算出的10位获得您所需要的最后一个数字,而不是说零

例如:号码为12345

  1. 钉在零:123450
  2. 计算LUHN校验和123450,其导致

    0 5 4 3 2 1 
    1 2 1 2 1 2 <-- factor 
    0 10 4 6 2 2 <-- product 
    0 1 0 4 6 2 2 <-- sum these to: 0+1+0+4+6+2+2=15 
    
  3. 径之和(15),模10,它给你5

  4. 位(5),不为零
  5. 计算10-5,它给你5,最后一位应该是5

所以结果是123455.

+0

谢谢,我意识到在这种情况下,我最右边的一对数字总是我的最后一个数字(因为我正在生成校验和数字)。 – 2009-09-13 23:31:32

2

你的PHP越野车,它会导致无限循环。 这是工作的版本,我使用的,从您的代码修改

功能卢恩($号){

$stack = 0; 
$number = str_split(strrev($number)); 

foreach ($number as $key => $value) 
{ 
    if ($key % 2 == 0) 
    { 
     $value = array_sum(str_split($value * 2)); 
    } 
    $stack += $value; 
} 
$stack %= 10; 

if ($stack != 0) 
{ 
    $stack -= 10;  $stack = abs($stack); 
} 


$number = implode('', array_reverse($number)); 
$number = $number . strval($stack); 

return $number; 

}

创建一个PHP和运行localhost Luhn(xxxxxxxx)确认。

+0

似乎没有越野车对我来说:http://www.ideone.com/y6bkh ... – 2010-12-05 14:49:00

2

BAD

我简直不能相信多少照出的实现也有在那里。

IDAutomation有一个.NET assembly with a MOD10() function创建,但它似乎并没有工作。在Reflector中,代码对于它应该做的事情来说太长了。


BAD

This mess of a page这实际上是当前链接到维基百科(!)为Javascript有几个验证实现,当我打电话每一个甚至不返回相同的值。


GOOD

page linked to from Wikipedia's Luhn page有一个JavaScript编码器,似乎工作:

// Javascript 
String.prototype.luhnGet = function() 
{ 
    var luhnArr = [[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8,1,3,5,7,9]], sum = 0; 
    this.replace(/\D+/g,"").replace(/[\d]/g, function(c, p, o){ 
     sum += luhnArr[ (o.length-p)&1 ][ parseInt(c,10) ] 
    }); 
    return this + ((10 - sum%10)%10); 
}; 

alert("54511187504546384725".luhnGet());​ 

GOOD

very useful EE4253 p年龄验证校验位并显示完整的计算和解释。


GOOD

我需要C#代码,并最终使用该code project code

// C# 
public static int GetMod10Digit(string data) 
     { 
      int sum = 0; 
      bool odd = true; 
      for (int i = data.Length - 1; i >= 0; i--) 
      { 
       if (odd == true) 
       { 
        int tSum = Convert.ToInt32(data[i].ToString()) * 2; 
        if (tSum >= 10) 
        { 
         string tData = tSum.ToString(); 
         tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString()); 
        } 
        sum += tSum; 
       } 
       else 
        sum += Convert.ToInt32(data[i].ToString()); 
       odd = !odd; 
      } 

      int result = (((sum/10) + 1) * 10) - sum; 
      return result % 10; 
     } 

GOOD

validation code in C#似乎为w ork,如果有点笨拙。我只是用它来检查以上是否正确。

+0

我实际上最终花费了*方式*太多时间试图找到工作代码,应该自己写。请记住,验证算法和检查算法基本相同 - 通过验证,您只需为字符串中的n-1个数字创建校验和,并与最后一位数字进行比较 – 2012-09-14 07:28:44

0

这是一个功能,可以帮助你,这是短期和它工作得很好。

function isLuhnValid($number) 
{ 
    if (empty($number)) 
     return false; 

    $_j = 0; 
    $_base = str_split($number); 
    $_sum = array_pop($_base); 
    while (($_actual = array_pop($_base)) !== null) { 
     if ($_j % 2 == 0) { 
      $_actual *= 2; 
      if ($_actual > 9) 
       $_actual -= 9; 
     } 
     $_j++; 
     $_sum += $_actual; 
    } 
    return $_sum % 10 === 0; 
}