生成 Luhn 校验和

2022-08-31 01:11:51

有很多用于验证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;
}

答案 1

编辑:对不起,我现在意识到你几乎已经有了我的全部答案,你刚刚错误地确定了使用哪个因子来表示哪个数字。

我现在的整个答案可以用这一句话来概括:

你把因子颠倒过来,根据数字的长度,你把错误的数字乘以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。

如果您最终得到的数字以零结尾,而 20 则数字有效。

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

  1. 附加一个额外的零,这样你的数字就会从 xyxyxyxy 变为 xyxyxyxy0
  2. 计算新数字的 luhn 校验和和
  3. 取和,模数为10,所以你得到一个从0到10的一位数
  4. 如果数字为 0,则恭喜,您的校验和数字为零
  5. 否则,计算 10 位数字以获得最后一位数字所需的内容,而不是该零

示例:数字为 12345

  1. 零点固定: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。

所以结果是123455。


答案 2

你的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并在您的本地主机Luhn(xxxxxxxx)中运行以进行确认。


推荐