14

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

7 に答える 7

10

編集:申し訳ありませんが、あなたはすでに私の答えのほとんどすべてを持っていることに気づきました。あなたはどの数字にどの要素を使用するかを間違って決定しただけです。

私の答え全体は、次の1つの文にまとめることができます。

係数が逆になっています。数値の長さに応じて、間違った桁に2を掛けています。


Luhnアルゴリズムに関するウィキペディアの記事をご覧ください。

チェックサムが半分の時間無効である理由は、チェックサムの半分の時間で数字の桁数が奇数になり、間違った桁が2倍になるためです。

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

このアルゴリズムでは、元の数値の個々の桁と、それらの「右から2桁ごと」の積の個々の桁を合計する必要があります。

したがって、右から、3 +(1 + 6)+ 2 +(1 + 4)+ 3を合計すると、20になります。

最終的に得られる数値がゼロで終わる場合(20はゼロ)、その数値は有効です。

さて、あなたの質問は、チェックサムを生成する方法を知りたいことを示唆しています。それは簡単です。次のようにします。

  1. 余分なゼロをタックして、あなたの数がxyxyxyxyからxyxyxyxy0になるようにします
  2. 新しい数値のluhnチェックサムの合計を計算します
  3. モジュラス10の合計をとると、0から10までの1桁が得られます。
  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になります。

于 2009-09-13T22:12:02.323 に答える
3

あなたの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)で実行して確認します。

于 2010-12-04T09:46:02.380 に答える
3

悪い

私は文字通り、そこにいくつの不器用な実装があるのか​​信じられません。

IDAutomationには、作成するMOD10()関数を備えた.NETアセンブリがありますが、機能していないようです。Reflectorでは、コードが長すぎて、とにかく実行することになっています。


悪い

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#のこの検証コードは、少し扱いに​​くい場合でも機能するようです。上記が正しいことを確認するために使用しました。

于 2012-09-13T00:26:53.003 に答える
0

元の質問/回答に基づいたgithubリポジトリがあります。見る

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

packagistでも入手できます

于 2013-02-06T13:00:05.900 に答える
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;
}
于 2017-08-29T02:08:13.093 に答える
0

C#に表示またはリンクされた他の回答が機能しなかったため、テスト済みのより説明的なC#バージョンを追加しました。

    /// <summary>
    /// Calculates Luhn Check Digit based on 
    /// https://en.wikipedia.org/wiki/Luhn_algorithm
    /// </summary>
    /// <param name="digits">The digits EXCLUDING the check digit on the end. 
    /// The check digit should be compared against the result of this method.      
    /// </param>
    /// <returns>The correct checkDigit</returns>
    public static int CalculateLuhnCheckDigit(int[] digits)
    {
        int sum = 0;
        bool isMultiplyByTwo = false;

        //Start the summing going right to left
        for (int index = digits.Length-1; index >= 0; --index) 
        {
            int digit = digits[index];

            //Every other digit should be multipled by two.
            if (isMultiplyByTwo) 
                digit *= 2;

            //When the digit becomes 2 digits (due to digit*2),
            //we add the two digits together.
            if (digit > 9) 
                digit = digit.ToString()
                  .Sum(character => (int)char.GetNumericValue(character));

            sum += digit;
            isMultiplyByTwo = !isMultiplyByTwo;
        }

        int remainder = sum % 10;

        //If theres no remainder, the checkDigit is 0.
        int checkDigit = 0; 

        //Otherwise, the checkDigit is the number that gets to the next 10
        if (remainder != 0)
            checkDigit = 10 - (sum % 10); 

        return checkDigit;
    }

その使用例:

    public static bool IsValid(string userValue)
    {
        //Get the check digit from the end of the value
        int checkDigit = (int)char.GetNumericValue(userValue[userValue.Length - 1]);

        //Remove the checkDigit for the luhn calculation
        userValue = userValue.Substring(0, userValue.Length - 1); 
        int[] userValueDigits = userValue.Select(ch => (int)char.GetNumericValue(ch))
                                         .ToArray();

        int originalLuhnDigit = CalculateLuhnCheckDigit(userValueDigits);

        //If the user entered check digit matches the calcuated one,
        //the number is valid.
        return checkDigit == originalLuhnDigit;
    }
于 2019-09-27T12:56:49.273 に答える
0

パリティチェックは右から開始する必要があります。

これを試して:

<?php

  function Luhn($digits) {

    $sum = 0;
    foreach (str_split(strrev($digits)) as $i => $digit) {
      $sum += ($i % 2 == 0) ? array_sum(str_split($digit * 2)) : $digit;
    }

    return $digits . (10 - ($sum % 10)) % 10;
  }

Luhnチェックサムを$inputに追加します

  $digits = Luhn($input);
  

Luhnチェックサムを含む番号を確認します。

  if ($digits == Luhn(substr($digits, 0, -1))) {
    // ... 
  }

チェックサム番号を取得します。

  $luhn_digit = substr(Luhn($digits), -1);
于 2022-02-25T23:05:01.797 に答える