2009-09-13 10 views
10

Istnieje wiele implementacji do sprawdzania poprawności sum kontrolnych Luhna, ale bardzo niewiele do ich generowania. Natknąłem się na this one, ale w moich testach okazało się, że jest błędny i nie rozumiem logiki kryjącej się za zmienną delta.Generowanie sum kontrolnych Luhna

Zrobiłem tę funkcję, która rzekomo powinna generować sumy kontrolne Luhna, ale z jakiegoś powodu nie zrozumiałem jeszcze, że wygenerowane sumy kontrolne są nieważne przez połowę czasu.

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

Kilka przykładów:

Luhn(3); // 37, invalid 
Luhn(37); // 372, valid 
Luhn(372); // 3728, invalid 
Luhn(3728); // 37283, valid 
Luhn(37283); // 372837, invalid 
Luhn(372837); // 3728375, valid 

Jestem sprawdzania sum kontrolnych wygenerowanych against this page, co robię źle tutaj?


Poniżej znajduje się funkcja robocza.

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

rzuciłem zmienną $ parzystości ponieważ nie trzeba go do tego celu, a do sprawdzenia:

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

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

    return false; 
} 
+2

Swoją drogą, weryfikacja sumy kontrolnej jest identyczna z wygenerowaniem i sprawdzeniem, czy jest równa zero - więc wszystkie te procedury "weryfikujące" mogą być również użyte do wygenerowania. –

+0

@Nick: Tak, ale to wymaga sprawdzenia 10 różnych cyfr, wolę na odwrót (sprawdź za pomocą funkcji generowania). –

+0

Co? Nie, wystarczy "zweryfikować" numer z dodanym 0, a następnie zastąpić ostatnią cyfrę (9-wynik). –

Odpowiedz

8

Edit: Niestety, zdaję sobie sprawę, że teraz miał prawie Moje strony całą odpowiedź już, właśnie błędnie ustalono, który czynnik należy użyć dla której cyfry.

Cała moja odpowiedź teraz można podsumować z tym jednym zdaniu:

Musisz czynnikiem odwrócony, jesteś pomnożenie błędne cyfry 2 w zależności od długości numeru.


Spójrz na Wikipedia article on the Luhn algorithm.

Powód, dla którego suma kontrolna jest nieważna w połowie okresu, polega na tym, że przy twoich kontrolach, połowa czasu ma nieparzystą liczbę cyfr, a następnie podwójna błędna cyfra.

Dla 37283, kiedy licząc od prawej, masz ten ciąg liczb:

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 

Algorytm wymaga, aby zsumować poszczególne cyfry z oryginalnego numeru, a poszczególne cyfry iloczyn tych "co dwie cyfry od prawej".

Więc z prawej strony, to suma 3 + (1 + 6) + 2 + (1 + 4) + 3, co daje 20.

Jeżeli liczba skończyć z końców z zera, co 20, numer jest ważny.

Teraz swoje podpowiedzi pytanie na was, którzy chcą wiedzieć, jak wygenerować sumę kontrolną, dobrze, że to łatwe, wykonaj następujące czynności:

  1. Tack na dodatkową zera, dzięki czemu liczba idzie z xyxyxyxy do xyxyxyxy0
  2. Oblicz sumę kontrolną Luhna dla nowego numeru
  3. Take sumę, moduł 10, więc masz jedną cyfrę od 0 do 10
  4. Jeśli cyfra jest 0, to gratulacje, Twoja cyfra kontrolna była zerowa
  5. W przeciwnym razie, należy obliczyć 10-cyfrowy, aby dostać to, czego potrzebujesz do ostatniej cyfry, zamiast tego zera

Przykład: Liczba: 12345

  1. Tack na zero: 123450
  2. Oblicz suma kontrolna Luhna do 123450, co skutkuje

    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. Take suma (15), moduł 10, co daje 5

  4. Cyfra (5), nie jest zerem
  5. Oblicz 10-5, co daje 5, ostatnia cyfra powinna być 5.

Więc wynik jest 123455.

+0

Dzięki, zdałem sobie sprawę, że moja cyfra po prawej stronie w tym przypadku jest zawsze moją ostatnią cyfrą (ponieważ generuję cyfrę kontrolną). –

2

Twój PHP buggy, prowadzi do nieskończonej pętli. To jest wersja działa, że ​​używam, modyfikowany kodzie

funkcja Luhna ($ liczba) {

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

}

Tworzenie php i uruchomić w swojej localhost Luhn (xxxxxxxx) do potwierdzenia.

+0

Nie wydaje mi się błędny: http: //www.ideone.com/y6bkh ... –

2

BAD

ja dosłownie nie mogę uwierzyć, jak wiele marne implementacje są tam.

IDAutomation ma .NET assembly with a MOD10() function do stworzenia, ale po prostu nie działa. W Reflectorze kod jest o wiele za długi na to, co i tak powinien robić.


BAD

This mess of a page która jest faktycznie obecnie związana z Wikipedii (!) Przez kilka implementacje JavaScript weryfikacyjne, które nawet nie zwracają taką samą wartość, gdy wzywam każdego z nich.


DOBRY

page linked to from Wikipedia's Luhn page posiada enkoder Javascript, który wydaje się działać:

// 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());​ 

DOBRY

Ten very useful EE4253 p Wiek weryfikuje cyfrę kontrolną, a także pokazuje pełne obliczenia i wyjaśnienia.


DOBRY

potrzebowałem kodu C# i skończyło się to 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; 
     } 

DOBRY

Ten validation code in C# wydaje się w ork, jeśli trochę nieporęczny. Właśnie użyłem tego, aby sprawdzić powyższe było prawidłowe.

+0

Tak naprawdę skończyłem wydając * sposób * za dużo czasu na znalezienie działającego kodu i powinienem sam to napisać. Pamiętaj, że algorytm sprawdzania poprawności i algorytm sprawdzania są zasadniczo takie same - z walidacją właśnie tworzysz sumę kontrolną dla n-1 cyfr w ciągu i porównujesz z ostatnią cyfrą –

0

Jest to funkcja, która mogłaby pomóc, to krótko i to działa dobrze.

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