Pregunta

Hay muchas implementaciones para validar las sumas de verificación de Luhn, pero muy pocas para generarlas. Me he encontrado con este , sin embargo, en mis pruebas se reveló que tenía errores y no entender la lógica detrás de la variable delta.

He realizado esta función que supuestamente debería generar sumas de verificación de Luhn, pero por alguna razón aún no he entendido que las sumas de verificación generadas son inválidas la mitad del tiempo.

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

Algunos ejemplos:

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

Estoy validando las sumas de verificación generadas en esta página , ¿qué estoy haciendo mal aquí?


Para referencia futura, aquí está la función de trabajo.

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

Eliminé la variable $ parity ya que no la necesitamos para este propósito y para verificar:

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

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

    return false;
}
¿Fue útil?

Solución

Editar : Lo siento, ahora me doy cuenta de que ya tenía casi toda mi respuesta, que había determinado incorrectamente qué factor utilizar para cada dígito.

Toda mi respuesta ahora se puede resumir con esta oración:

Tiene el factor invertido, está multiplicando los dígitos incorrectos por 2 dependiendo de la longitud del número.


Eche un vistazo al artículo de Wikipedia sobre el algoritmo Luhn .

La razón por la cual su suma de verificación no es válida la mitad del tiempo es que con sus cheques, la mitad de las veces su número tiene un número impar de dígitos, y luego duplica el dígito incorrecto.

Para 37283, al contar desde la derecha, obtiene esta secuencia de números:

  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

El algoritmo requiere que sume los dígitos individuales del número original y los dígitos individuales del producto de esos "cada dos dígitos desde la derecha".

Entonces, desde la derecha, sumas 3 + (1 + 6) + 2 + (1 + 4) + 3, lo que te da 20.

Si el número con el que termina termina con un cero, que es 20, el número es válido.

Ahora, su pregunta sugiere que desea saber cómo generar la suma de comprobación, bueno, eso es fácil, haga lo siguiente:

  1. Agregue un cero adicional, por lo que su número va de xyxyxyxy a xyxyxyxy0
  2. Calcule la suma de suma de comprobación de luhn para el nuevo número
  3. Tome la suma, módulo 10, para obtener un solo dígito de 0 a 10
  4. Si el dígito es 0, entonces felicidades, su dígito de suma de verificación era cero
  5. De lo contrario, calcule 10 dígitos para obtener lo que necesita para el último dígito, en lugar de ese cero

Ejemplo: el número es 12345

  1. Tack on a zero: 123450
  2. Calcule la suma de comprobación de luhn para 123450, que da como resultado

    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. Toma la suma (15), módulo 10, que te da 5

  4. Dígito (5), no es cero
  5. Calcule 10-5, que le da 5, el último dígito debe ser 5.

Entonces el resultado es 123455.

Otros consejos

tu php tiene errores, conduce a un bucle infinito. Esta es la versión de trabajo que estoy usando, modificada desde su código

  

función Luhn ($ número) {

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

}

Cree un php y ejecútelo en su localhost Luhn (xxxxxxxx) para confirmar.

BAD

Literalmente no puedo creer cuántas implementaciones malas hay por ahí.

  

IDAutomation tiene una .NET ensamblado con una función MOD10 () para crear pero simplemente no parece funcionar. En Reflector, el código es demasiado largo para lo que se supone que debe hacer de todos modos.


BAD

Este lío de una página que actualmente está vinculado desde Wikipedia (!) Para Javascript tiene varias implementaciones de verificación que ni siquiera devuelven el mismo valor cuando llamo a cada una.


GOOD

La página vinculada a la página Luhn de Wikipedia tiene un codificador Javascript que parece funcionar:

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

Esta muy útil EE4253 verifica el dígito de verificación y también muestra el cálculo completo y la explicación.


GOOD

Necesitaba el código C # y terminé usando esto código del proyecto de código :

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

Este código de validación en C # parece funcionar, aunque sea un poco difícil de manejar. Simplemente lo usé para verificar que lo anterior era correcto.

Ahora hay un repositorio de github basado en la pregunta / respuesta original. Ver

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

También está disponible en packagist

Esta es una función que podría ayudarlo, es corta y funciona bien.

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

    

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>j = 0;

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>base = str_split($number);

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>sum = array_pop(

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>base); while ((

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>actual = array_pop(

Esta es una función que podría ayudarlo, es corta y funciona bien.

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

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>j % 2 == 0) {

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>actual *= 2; if (

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>actual > 9)

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>actual -= 9; }

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>j++;

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>sum +=

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>actual; } return

Esta es una función que podría ayudarlo, es corta y funciona bien.

<*>sum % 10 === 0; }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top