문제

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

생성된 체크섬을 검증하고 있습니다. 이 페이지에 반대, 내가 여기서 뭘 잘못하고 있는 걸까요?


나중에 참고할 수 있도록 작업 기능은 다음과 같습니다.

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 알고리즘에 대한 Wikipedia 기사.

체크섬의 절반이 유효하지 않은 이유는 수표를 사용하면 숫자의 숫자가 홀수 숫자를 가지고 있고 잘못된 자리를 두 배로 늘리기 때문입니다.

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. 여분의 0에 압정이 있으므로 숫자는 xyxyxyxy에서 xyxyxyxy0으로 이동합니다.
  2. 새 번호의 Luhn 체크섬 합계를 계산하십시오
  3. 합계, 모듈러스 10을 가져 가면 0에서 10까지의 단일 자릿수를 얻습니다.
  4. 숫자가 0이면 축하하면 체크섬 숫자가 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)는 0이 아닙니다
  5. 10-5를 계산하여 5, 마지막 자리는 5이어야합니다.

결과는 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로 링크되어 있는 여기에는 호출할 때 동일한 값을 반환하지 않는 여러 확인 구현이 있습니다.


좋은

그만큼 Wikipedia의 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