有很多验证 Luhn 校验和的实现,但生成它们的实现却很少。我遇到过 这个 然而,在我的测试中,它显示出有问题,而且我不理解 delta 变量背后的逻辑。

我已经创建了这个函数,据说应该生成 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

我正在验证生成的校验和 针对此页面, ,我在这里做错了什么?


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

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;
}

我删除了 $parity 变量,因为我们不需要它用于此目的,并验证:

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

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

    return false;
}
有帮助吗?

解决方案

编辑:很抱歉,我现在已经意识到你已经有了几乎所有的答案,你只是错误地确定了哪个因素用于哪个数字。

现在我的整个答案可以用这句话总结:

你有一个因素反转,你将错误的数字乘以2取决于数字的长度。


查看维基百科有关Luhn算法的文章

你的校验和一半时间无效的原因是你的支票是你的号码有一个奇数位数的一半,然后你把错误的数字加倍。

对于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。

如果你最终得到的数字以0结尾,而20就是,则该数字有效。

现在,您的问题暗示您想知道如何生成校验和,嗯,这很简单,请执行以下操作:

  1. 多加零,所以你的号码从xyxyxyxy到xyxyxyxy0
  2. 计算新数字的luhn校验和总和
  3. 取总和,模数10,这样你就得到一个从0到10的单个数字
  4. 如果数字为0,那么祝贺你的校验和数字为零
  5. 否则,计算10位数以获得最后一位数而不是零
  6. 所需的数字

    示例:数字是12345

    1. Tack on the zero:123450
    2. 计算123450的luhn校验和,得到

      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。
    6. 结果是123455。

其他提示

你的php是错误的,它导致无限循环。 这是我正在使用的工作版本,从您的代码中修改

  

函数Luhn($ number){

$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)中运行以确认。

坏的

我简直不敢相信有多少糟糕的实现。

IDAutomation 有一个 具有 MOD10() 函数的 .NET 程序集 创造,但它似乎不起作用。在 Reflector 中,代码对于它应该做的事情来说太长了。


坏的

这一页乱七八糟 实际上,当前从 Wikipedia(!) 链接到的 JavaScript 有几种验证实现,当我调用每个验证实现时,它们甚至不会返回相同的值。


好的

页面链接自维基百科的 Luhn 页面 有一个 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());​

好的

非常有用的EE4253 页面验证校验位并显示完整的计算和解释。


好的

我需要 C# 代码并最终使用了这个 代码 项目代码:

// 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;
        }

好的

C# 中的验证代码 似乎可行,虽然有点笨拙。我只是用它来检查上面的内容是否正确。

现在有一个基于原始问题/答案的github回购。见

https://github.com/xi-project/xi-algorithm

它也可以在packagist上找到

这是一个可以帮助你的功能,它很短,而且效果很好。

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; }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top