Valid Credit Card Number?

Credit card numbers are not random; there are a number of embedded codes and there is an overall structural requirement. This script (for the fun of it), validates the structure of a 16-digit number as a potential credit card number. It’s called the Luhn Algorithm. The rest of the code (for the curious) is explained in this Stumbleupon entry.

(*
Take any real credit card number and double every other digit starting on the right.
For each two-digit double, add the digits, otherwise just use the number. 
Add these results to all of the original numbers. 
If the sum is divisible by 10, the credit card number is properly structured.
This is the Luhn Algorithm that all credit cards use.
*)

validate("4417123456789113") -- uses text to avoid size limit on numbers

to validate(tNum)
	set numList to characters of tNum
	if (count numList) ≠ 16 then
		display dialog "Must Be 16 Digits!"
		return
	end if
	set tSum to 0
	repeat with k from 2 to 16 by 2 -- add every even placed entry
		set tSum to tSum + (item k of numList)
	end repeat
	repeat with j from 15 to 1 by -2 -- double, adjust and add odd placed entries
		set double to 2 * (item j of numList)
		if double > 9 then set double to 1 + double mod 10 -- just add the digits
		set tSum to tSum + double
	end repeat
	if tSum mod 10 is 0 then
		display dialog "Number Structure is Valid."
	else
		display dialog "Cannot Be a Credit Card Number!"
	end if
end validate

ASIDE: Nigel Garvey and other whizzes with modulo arithmetic are invited to make this much more elegant. :slight_smile:

Thanks, Adam. That’s very interesting. :slight_smile:

You can lose one of the repeats like this:

validate("4417123456789113") -- uses text to avoid size limit on numbers

to validate(tNum)
	if (count tNum) ≠ 16 then
		display dialog "Must Be 16 Digits!"
		return
	end if
	set numList to characters of tNum
	set tSum to 0
	repeat with k from 1 to 15 by 2
		tell (item k of numList) * 2 to set tSum to tSum + it div 10 + it mod 10 + (item (k + 1) of numList)
	end repeat
	if tSum mod 10 is 0 then
		display dialog "Number Structure is Valid."
	else
		display dialog "Cannot Be a Credit Card Number!"
	end if
end validate

Or numerically:

validate("4417123456789113")

to validate(tNum)
	if (count tNum) ≠ 16 then
		display dialog "Must Be 16 Digits!"
		return
	end if
	set n to tNum as number
	set tSum to 0
	repeat 8 times
		tell n mod 100 div 10 * 2 to set tSum to tSum + it div 10 + it mod 10 + n mod 10
		set n to n div 100
	end repeat
	if tSum mod 10 is 0 then
		display dialog "Number Structure is Valid."
	else
		display dialog "Cannot Be a Credit Card Number!"
	end if
end validate

I wish you wouldn’t post things like this just as I’m going to bed. :wink:

In fact, since units in addition results aren’t affected by carries, there’s no need to mod by 10 during the calculation. The mod in the test at the end is enough:

validate("4417123456789113")

to validate(tNum)
	if (count tNum) ≠ 16 then
		display dialog "Must Be 16 Digits!"
		return
	end if
	set n to tNum as number
	set tSum to 0
	repeat 8 times
		tell n mod 100 div 10 * 2 to set tSum to tSum + it div 10 + it + n
		set n to n div 100
	end repeat
	if tSum mod 10 is 0 then
		display dialog "Number Structure is Valid."
	else
		display dialog "Cannot Be a Credit Card Number!"
	end if
end validate

Wow.

A more interesting variant is:

This contains exactly the same number of the same operators and doesn’t inflate tSum to such a huge size, which may (possibly) reduce the risk of errors.

Very interesting. It’s use could be for assistant scripts or transferred to ASOC or Objective-C for use in buying things.
But, I ask, why do numbers higher than a certain amount (and not in quotes, of course) need to be converted to a different format, and why does AppleScript take the value differently?