Domanda

Esistono molte implementazioni per la convalida dei checksum Luhn ma pochissime per la loro generazione. Mi sono imbattuto in questo tuttavia nei miei test si è rivelato essere difettoso e io no capire la logica dietro la variabile delta.

Ho creato questa funzione che presumibilmente dovrebbe generare checksum Luhn, ma per qualche motivo non ho ancora capito che i checksum generati non sono validi metà del tempo.

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

Alcuni esempi:

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

Sto convalidando i checksum generati rispetto a questa pagina , cosa sto facendo di sbagliato qui?


Per riferimento futuro, ecco la funzione operativa.

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

Ho abbandonato la variabile $ parity poiché non ne abbiamo bisogno per questo scopo e per verificare:

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

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

    return false;
}
È stato utile?

Soluzione

Modifica : mi spiace, ora mi rendo conto che avevi già quasi tutta la mia risposta, avevi appena erroneamente determinato quale fattore usare per quale cifra.

La mia intera risposta ora può essere riassunta con questa singola frase:

Hai il fattore invertito, stai moltiplicando le cifre sbagliate per 2 a seconda della lunghezza del numero.


Dai un'occhiata all'articolo Wikipedia sull'algoritmo Luhn .

La ragione per cui il tuo checksum non è valido per metà del tempo è che con i tuoi controlli, per metà del tempo il tuo numero ha un numero dispari di cifre, quindi raddoppia la cifra sbagliata.

Per 37283, quando si conta da destra, si ottiene questa sequenza di numeri:

  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

L'algoritmo richiede di sommare le singole cifre dal numero originale e le singole cifre del prodotto di quelle "ogni due cifre dalla destra".

Quindi da destra, sommi 3 + (1 + 6) + 2 + (1 + 4) + 3, che ti dà 20.

Se il numero con cui finisci termina con uno zero, cosa che fa 20, il numero è valido.

Ora, la tua domanda suggerisce che vuoi sapere come generare il checksum, beh, è ??facile, fai quanto segue:

  1. Contrassegna uno zero aggiuntivo, quindi il tuo numero passa da xxyxyxy a xxyxyxy0
  2. Calcola la somma di checksum luhn per il nuovo numero
  3. Prendi la somma, modulo 10, in modo da ottenere una singola cifra da 0 a 10
  4. Se la cifra è 0, quindi congratulazioni, la cifra del checksum era zero
  5. Altrimenti, calcola 10 cifre per ottenere ciò di cui hai bisogno per l'ultima cifra, anziché quello zero

Esempio: il numero è 12345

  1. Tack su uno zero: 123450
  2. Calcola il checksum luhn per 123450, che risulta in

    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. Prendi la somma (15), modulo 10, che ti dà 5

  4. Cifra (5), non è zero
  5. Calcola 10-5, che ti dà 5, l'ultima cifra dovrebbe essere 5.

Quindi il risultato è 123455.

Altri suggerimenti

il tuo php è difettoso, conduce in un ciclo infinito. Questa è la versione funzionante che sto usando, modificata dal tuo codice

  

funzione Luhn ($ numero) {

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

}

Crea un php ed esegui nel tuo host locale Luhn (xxxxxxxx) per confermare.

BAD

Non riesco letteralmente a credere a quante implementazioni scadenti ci siano là fuori.

  

IDAutomation ha un assembly .NET con una funzione MOD10 () per creare ma non sembra funzionare. In Reflector il codice è troppo lungo per quello che dovrebbe fare comunque.


BAD

Questo casino di una pagina a cui è attualmente collegato da Wikipedia (!) Per Javascript ha diverse implementazioni di verifica che non restituiscono nemmeno lo stesso valore quando le chiamo ognuna.


BUONA

La pagina collegata alla pagina Luhn di Wikipedia ha un codificatore Javascript che sembra funzionare:

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

BUONA

Questa molto utile EE4253 verifica la cifra di controllo e mostra anche il calcolo e la spiegazione completi.


BUONA

Avevo bisogno del codice C # e ho finito per usarlo codice codice progetto :

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

BUONA

Questo codice di convalida in C # sembra funzionare, anche se un po 'ingombrante. L'ho usato solo per verificare che quanto sopra fosse corretto.

Ora c'è un repository github basato sulla domanda / risposta originale. Vedi

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

È disponibile anche su packagist

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

function isLuhnValid($number)
{
    if (empty($number))
        return false;

    

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>j = 0;

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>base = str_split($number);

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>sum = array_pop(

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>base); while ((

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>actual = array_pop(

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>base)) !== null) { if (

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>j % 2 == 0) {

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>actual *= 2; if (

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>actual > 9)

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>actual -= 9; }

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>j++;

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>sum +=

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>actual; } return

Questa è una funzione che potrebbe aiutarti, è breve e funziona perfettamente.

<*>sum % 10 === 0; }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top