2009-09-13 235 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; 
}