Алгоритм Луна (Luhn Algorithm)

В функции ValidateCard применяется алгоритм, названный алгоритмом Луна, кото­рый разработал специалист компании IBM в 1960 гг. Алгоритм Луна действует, т. к. компании, выпускающие кредитные карты, следуют его правилам. Другими словами, они выпускают только такие номера, которые считаются допустимыми с точки зрения алгоритма Луна.

Полное объяснение алгоритма Луна можно найти на Web-странице http://en.wikipedia.org/wiki/Luhn_algorithm.Далее приведено описание его принципа действия в версии журнала "Reader's Digest".

1. Удвойте каждую вторую цифру номера кредитной карты, начиная с последней цифры номера. Оставьте все цифры с четным2 номером неизменными. Например, номер 1111 превратится вномер2121.

2. Если в процессе удвоения получается число большее 9, сложите две цифры полученного результата вместе и поставьте их на место исходной цифры. Например, номер 1166 превратится в номер 2136. Вторая от конца цифра 6 была удвоена (до 12) и цифры результата (1 и 2) сложили вместе (для получения 3).

3. Сложите все цифры получившегося номера вместе. Если у вас в данный момент номер 2136, сложите вместе 2+1+3+6 (что даст 12).

4. Если результат заканчивается 0 (или иначе, если он кратен 10), номер карты допустимый. В противном случае — нет.

Алгоритм Луна проверяет, может ли предоставленный вами номер быть номером реаль­ной кредитной карты. Но он делает только то, что делает. Этот алгоритм не может обна­ружить номер кредитной карты, технически приемлемый, но на самом деле не присво­енный никакому банковскому счету (и ясно, что не может определить финансовое положение владельца счета и наличие на счету требуемого для покупки лимита).

 

Далее приведен полный программный код функции ValidateCard. Все строки кода пронумерованы, поэтому вы можете разбить его на элементарные порции (построчные объ­яснения даются после кода):

1 Function ValidateCard(CardNumber As String)

' Это промежуточный итог (создаваемый с помощью алгоритма Луна)

2 Dim SumOfDigits

3 SumOfDigits = 0

' Эта переменная определяет, в какой вы находитесь позиции,

' нечетной или четной.

' Вы начинаете с нечетной позиции (1)

4 Dim OddNumbered

5 OddNumbered = True

2 В этом случае четные от начала номера, применяемого в качестве примера. — Пер.


6 Dim i

7 For i = Len(CardNumber) To 1 Step -1

8 Dim CurrentNumber

9 CurrentNumber = Mid(CardNumber, i, 1)

10 If OddNumbered = False Then

' Цифра удваивается

11 CurrentNumber = CurrentNumber * 2

12 If CurrentNumber >= 10 Then '

' Если результат состоит из двух цифр, они складываются.

' Это странная часть, поскольку нужно использовать

' функции преобразования строк

13 Dim NumText As String

14 NumText = CurrentNumber

15 CurrentNumber = Val(Left(NumText, 1)) +

16 Val(Right(NumText, 1))

17 End If

18 End If

' К промежуточному итогу добавляется полученное число

19 " SumOfDigits = SumOfDigits + CurrentNumber


‘Переход из нечетной позиции в четную или наоборот.

' Эта строка кода изменяет значение True на False или

' False на True

20 OddNumbered = Not OddNumbered

21 Next


' Если сумма кратна 10, номер допустимый

22 If SumOfDigits Mod 10 = 0 Then

23 ValidateCard = True

24 Else

25 ValidateCard = False

26 End If

27 End Function


Функция работает следующим образом.

■ В строке 1 объявляется функция. Обратите внимание на то, что у функции один параметр — текст с номером кредитной карты. Он явно определяется как строка с помощью оборота As String. Таким образом, вы избегаете ошибок, возникающих при попытке передать в функцию число.

■ В строках 2—3 создается переменная, хранящая в течение всего процесса обработки промежуточный итог.

■ В строках 4—5 создается переменная, которая следит за тем, в какой позиции номера вы находитесь, четной или нечетной, считая от конца номера.

■ В строках 6—7 начинается цикл For/Next. Этот цикл немного отличается от виденных вами ранее циклов, поскольку у него в конце есть выражение Step -1. Оно сообщает о том, что после каждого прохода цикла из счетчика вычитается 1 (в отличие от добавления 1 при стандартном поведении). Вы можете обрабатывать номер от конца к началу.

 

 

Примечание

В цикле применен еще один прием — нижнее граничное значение задается с помощью функ­ции Len, которая возвращает длину текстового фрагмента. Другими словами, если номер кре­дитной карты состоит из 11 цифр, этот код выполняется 11 раз (один раз для каждой цифры).

 

■ В строках 8—9 извлекается цифра в текущей позиции, на которую указывает счетчик цикла. Функция Mid позволяет вырезать одну цифру.

■ В строке 10 проверяется, находится ли полученная цифра в четной или нечетной позиции, считая от конца номера.

Строки 11—17 выполняются, только если позиция цифры не кратна двум, считая от конца номера. В этом случае ее следует удвоить (строка 11). Если получилось двузначное число, его цифры нужно сложить (строки 13—15).

■ В строке 19 текущее число добавляется к промежуточному итогу. Если вы находитесь в четной позиции, число не менялось. Если вы в нечетной позиции, число было удвоено и скомбинировано.

■ В строке 20 гарантируется переход из четной позиции в нечетную позицию (и обратно).

■ В строке 21 выполняется переход к строке 6 и повторение цикла для следующей цифры в номере кредитной карты.

■ В строках 22—26 проверяется окончательный итог. Если он кратен 10, номер допустимый. Для проверки применяется операция Mod, выполняющая деление и извлекающая остаток от деления нацело (Если остатка нет при делении числа на 10, вы знаете, что оно без проблем делится нацело.)

Может потребоваться некоторое время для того, чтобы разобраться в работе функции от начала до конца и выяснить точно, что происходит, но в конце концов все это относится к основным элементам языка VB, таким как условия, циклы и переменные. Если вы действи­тельно хотите изучить данный пример, его можно посмотреть в действии с помощью средств отладки.

После завершения создания функции, подобной ValidateCard, ее можно вызвать для проверки соответствия номера кредитной карты.


Далее приведен пример, реагирующий на ввод данных кредитной карты в текстовое по­ле, названное CardNumber:

Private Sub CardNumber_BeforeUpdate(Cancel As Integer)

If ValidateCard(CardNuraber) Then

MsgBox "Your card is valid," Else.

MsgBox "Your card is invalid. " & _

"Did you forget a number, or are you trying to cheat us?" Cancel = True

End If

End Sub

Для проверки выполните приведенный код и введите один из номеров ваших кредитных карт в поле CardNumber, как показано на рис. 17.3.

 
 

Рис. 17.3.Эта форма демонстрирует работу функции Validate Card в форме AddCreditCard(вставка кредитной карты) из БД Boutique Fudge . Когда бы ни менялось поле CardNumber,процедура проверяет его допустимость и отменяет изменения, если значение не приемлемо