Генерация контрольных сумм Луна
-
07-07-2019 - |
Вопрос
Существует множество реализаций для проверки контрольных сумм Луна, но очень мало для их генерации.я сталкивался Вот этот однако в моих тестах выяснилось, что он содержит ошибки, и я не понимаю логику переменной дельта.
Я создал эту функцию, которая предположительно должна генерировать контрольные суммы Луна, но по какой-то причине, которую я еще не понял, сгенерированные контрольные суммы в половине случаев недействительны.
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 - действительным.
Теперь ваш вопрос намекает на то, что вы хотите знать, как сгенерировать контрольную сумму, ну, это просто, сделайте следующее:
<Ол>Пример: номер 12345
<Ол>Рассчитайте контрольную сумму Луна для 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
Итак, результат - 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;
}