Вопрос

Существует множество реализаций для проверки контрольных сумм Луна, но очень мало для их генерации.я сталкивался Вот этот однако в моих тестах выяснилось, что он содержит ошибки, и я не понимаю логику переменной дельта.

Я создал эту функцию, которая предположительно должна генерировать контрольные суммы Луна, но по какой-то причине, которую я еще не понял, сгенерированные контрольные суммы в половине случаев недействительны.

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;
}
Это было полезно?

Решение

Изменить . Извините, теперь я понимаю, что у вас уже был почти весь мой ответ, вы просто неправильно определили, какой коэффициент использовать для какой цифры.

Весь мой ответ теперь можно обобщить одним предложением:

Вы поменяли множитель, вы умножаете неправильные цифры на 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

Алгоритм требует, чтобы вы суммировали отдельные цифры от исходного числа и отдельные цифры произведения этих "каждые две цифры справа".

Итак, справа вы получаете 3 + (1 + 6) + 2 + (1 + 4) + 3, что дает вам 20.

Если число, которое вы заканчиваете, заканчивается нулем, а 20 - действительным.

Теперь ваш вопрос намекает на то, что вы хотите знать, как сгенерировать контрольную сумму, ну, это просто, сделайте следующее:

<Ол>
  • Прибавьте дополнительный ноль, чтобы ваш номер перешел от ксиоксиокси к ксиоксиокси0
  • Рассчитайте сумму контрольной суммы Луна для нового номера
  • Возьмите сумму, модуль 10, чтобы получить одну цифру от 0 до 10
  • Если цифра 0, то поздравляю, ваша контрольная сумма была нулевой
  • В противном случае вычислите 10 цифр, чтобы получить то, что вам нужно для последней цифры, вместо этого нуля
  • Пример: номер 12345

    <Ол>
  • Придерживайтесь ноль: 123450
  • Рассчитайте контрольную сумму Луна для 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
    
  • Возьмите сумму (15), модуль 10, который дает вам 5

  • Цифра (5), не ноль
  • Рассчитайте 10-5, что дает 5, последняя цифра должна быть 5.
  • Итак, результат - 123455.

    Другие советы

    ваш 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 и запустите на своем локальном хосте Luhn(xxxxxxxx) для подтверждения.

    ПЛОХОЙ

    Я буквально не могу поверить, сколько существует паршивых реализаций.

    В IDAutomation есть Сборка .NET с функцией MOD10() создать, но, похоже, это не работает.В Reflector код слишком длинный для того, что он должен делать.


    ПЛОХОЙ

    Этот беспорядок на странице который на самом деле в настоящее время связан с Википедией (!) для Javascript, имеет несколько реализаций проверки, которые даже не возвращают одно и то же значение, когда я вызываю каждую из них.


    ХОРОШИЙ

    А страница, ссылка на которую находится на странице Луна в Википедии имеет кодировщик 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#
    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# кажется, работает, хотя и немного громоздко.Я просто использовал его, чтобы проверить правильность вышеизложенного.

    Теперь есть репозиторий github, основанный на оригинальном вопросе / ответе. Смотрите

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

    Это также доступно в Packagist

    Это функция, которая может вам помочь, она короткая и отлично работает.

    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; }
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top