Javascript Luhn算法的实现
我正在尝试实现对信用卡号码的简单验证。我读到了关于Luhn算法的内容:Javascript Luhn算法的实现,javascript,algorithm,luhn,datastructure,lookuptable,creditcard,validation,bitlist,Javascript,Algorithm,Luhn,Datastructure,Lookuptable,Creditcard,Validation,Bitlist,我正在尝试实现对信用卡号码的简单验证。我读到了关于Luhn算法的内容: 从最右边的校验位开始计数,然后移动 左,每第二个数字的值加倍 对乘积的数字求和(例如,10:1+0=1,14:1+4=5) 以及原始编号中的无疑问数字 如果总模10等于0(如果总和以零结束) 根据Luhn公式,该数字是有效的;否则就是 无效 在维基百科上,Luhn算法的描述很容易理解。然而,我也看到了Luhn算法的其他实现和(存档) 这些实现工作得很好,但我不明白为什么它们可以使用数组来完成这项工作。他们使用的数组似乎与Lu
他们为什么使用数组?它们的意义是什么,以及如何使用它们来实现维基百科描述的算法?数组
[0,1,2,3,4,-4,-3,-2,-1,0]
用作查找数组,用于查找0-9中的数字与其值的2倍数字和之间的差。例如,对于数字8,8和(2*8)=16->1+6=7之间的差值为7-8=-1
这是一个图形表示,其中{n}代表n的数字之和
[{0*2}-0, {1*2}-1, {2*2}-2, {3*2}-3, {4*2}-4, {5*2}-5, {6*2}-6, {7*2}-7....]
| | | | | | | |
[ 0 , 1 , 2 , 3 , 4 , -4 , -3 , -2 ....]
您列出的算法只是对所有数字求和,对于每个偶数点数字,使用数组查找差异,并将其应用于总和。代码如下:
var LuhnCheck = (function()
{
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
return function(str)
{
var counter = 0;
var incNum;
var odd = false;
var temp = String(str).replace(/[^\d]/g, "");
if ( temp.length == 0)
return false;
for (var i = temp.length-1; i >= 0; --i)
{
incNum = parseInt(temp.charAt(i), 10);
counter += (odd = !odd)? incNum : luhnArr[incNum];
}
return (counter%10 == 0);
}
})();
变量计数器
是奇数位置的所有数字加上偶数位置的两位数之和,当两位数超过10时,我们将两个数字相加(例如:6*2->12->1+2=3)
您所询问的数组是所有可能的双精度运算的结果
var luhnArr=[0,2,4,6,8,1,3,5,7,9]代码>
- 0*2=0-->0
- 1*2=2-->2
- 2*2=4-->4
- 3*2=6-->6
- 4*2=8-->8
- 5*2=10-->1+0-->1
- 6*2=12-->1+2-->3
- 7*2=14-->1+4-->5
- 8*2=16-->1+6-->7
- 9*2=18-->1+8-->9
比如说
luhnArr[3] --> 6 (6 is in 3rd position of the array, and also 3 * 2 = 6)
luhnArr[7] --> 5 (5 is in 7th position of the array, and also 7 * 2 = 14 -> 5 )
如果你想计算校验和,这段代码非常简洁,在我的随机测试中似乎很有效
注意:本页上的验证算法并不都有效
// 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());
这是我的紧凑型Luhn验证器:
var luhn_validate = function(imei){
return !/^\d+$/.test(imei) || (imei.split('').reduce(function(sum, d, n){
return n===(imei.length-1)
? 0
: sum + parseInt((n%2)? d: [0,2,4,6,8,1,3,5,7,9][d]);
}, 0)) % 10 == 0;
};
适用于CC和IMEI号码。Fiddle:不幸的是,上面的代码都不适合我。但我找到了一个有效的解决方案
// takes the form field value and returns true on valid number
function valid_credit_card(value) {
// accept only digits, dashes or spaces
if (/[^0-9-\s]+/.test(value)) return false;
// The Luhn Algorithm. It's so pretty.
var nCheck = 0, nDigit = 0, bEven = false;
value = value.replace(/\D/g, "");
for (var n = value.length - 1; n >= 0; n--) {
var cDigit = value.charAt(n),
nDigit = parseInt(cDigit, 10);
if (bEven) {
if ((nDigit *= 2) > 9) nDigit -= 9;
}
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) == 0;
}
查找表或数组可以简化算法实现—节省许多代码行—从而提高性能。。。如果查找索引的计算很简单,或者更简单,并且阵列的内存占用是可以承受的
另一方面,理解特定的查找数组或数据结构是如何形成的有时可能相当困难,因为相关的算法实现乍一看可能与原始算法规范或描述大不相同
使用查找表的指示是面向数字的算法,具有简单的算术、简单的比较和结构相同的重复模式,当然还有非常有限的值集
本线程中的许多答案适用于不同的查找表,并与不同算法的查找表一起实现相同的Luhn算法。大多数实现都使用查找数组来避免麻烦地计算出双位数的值:
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
//
// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
// | | | | | | | | | |
//
// - d-igit=index: 0 1 2 3 4 5 6 7 8 9
// - 1st
// calculation: 2*0 2*2 2*2 2*3 2*4 2*5 2*6 2*7 2*8 2*9
// - intermeduate
// value: = 0 = 2 = 4 = 6 = 8 =10 =12 =14 =16 =18
// - 2nd
// calculation: 1+0 1+2 1+4 1+6 1+8
//
// - final value: 0 2 4 6 8 =1 =3 =5 =7 =9
//
var luhnFinalValue = luhnArray[d]; // d is numeric value of digit to double
获取luhnFinalValue的等效实现如下所示:
var luhnIntermediateValue = d * 2; // d is numeric value of digit to double
var luhnFinalValue = (luhnIntermediateValue < 10)
? luhnIntermediateValue // (d ) * 2;
: luhnIntermediateValue - 10 + 1; // (d - 5) * 2 + 1;
function luhnValid3(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr);
return (s + [0,1,2,3,4,5,6,7,8,9,0,2,4,6,8,1,3,5,7,9][d+((e=!e)?0:10)]);
}
,0
) % 10 == 0
);
}
为了实现此线程,必须提到更多的查找表选项:
- 把变量调整成两位数怎么样?@yngum发布的
- 如何使用查找表的所有内容呢?——如@Simon_Weaver所述——其中非双精度数字的值也取自查找表
- 只需一个查找表就可以了,这是受到广泛讨论的luhnValid()函数中使用偏移量的启发
后者的代码(使用reduce)可能如下所示:
var luhnIntermediateValue = d * 2; // d is numeric value of digit to double
var luhnFinalValue = (luhnIntermediateValue < 10)
? luhnIntermediateValue // (d ) * 2;
: luhnIntermediateValue - 10 + 1; // (d - 5) * 2 + 1;
function luhnValid3(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr);
return (s + [0,1,2,3,4,5,6,7,8,9,0,2,4,6,8,1,3,5,7,9][d+((e=!e)?0:10)]);
}
,0
) % 10 == 0
);
}
对于关闭lunValid4()——非常紧凑——并且只使用“老式”(兼容)JavaScript——和一个查找表:
function luhnValid4(cardNo) { // cardNo as a string w/ digits only
var s = 0, e = false, p = cardNo.length; while (p > 0) { p--;
s += "01234567890246813579".charAt(cardNo.charAt(p)*1 + ((e=!e)?0:10)) * 1; }
return (s % 10 == 0);
}
卡罗拉:字符串可以看作是字符的查找表…;-)
一个很好的查找表应用程序的一个完美例子是对位列表中的设置位进行计数——在(解释的)高级语言中(非常)长的8位字节字符串中设置的位(其中任何位操作都非常昂贵)。查找表有256个条目。每个条目都包含一个无符号8位整数中设置的位数,该整数等于该条目的索引。遍历字符串并获取无符号8位字节的相等值,以从查找表中访问该字节的位数。即使对于低级语言(如汇编程序/机器代码),查找表也是一种方法。。。特别是在微代码(指令)可以在一条(单个CISC)指令中处理多达256个或更多字节的环境中
一些注意事项:
- numberString*1和parseInt(numberStr)的作用大致相同
- 有一些多余的缩进、括号等。。。支持我的大脑更快地理解语义。。。但有些我想省略的,实际上是必需的。。。什么时候
它涉及到以缩写形式的算术运算,value if then else表达式作为术语
- 某些格式对您来说可能是新的;例如,我使用逗号和
延续与延续在同一行,我“关闭”了东西-半个制表符-缩进到“开始”项
function luhnValid2(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr); // reduce arg-0 - callback fnc
return (s + ((e = !e) ? d : [0,2,4,6,8,1,3,5,7,9][d]));
} // /end of callback fnc
,0 // reduce arg-1 - prev value for first iteration (sum)
) % 10 == 0
);
}
function luhnValid3(cardNo) { // cardNo as a string w/ digits only
var d = 0, e = false; // e = even = n-th digit counted from the end
return ( cardNo.split("").reverse().reduce(
function(s,dstr){ d = parseInt(dstr);
return (s + [0,1,2,3,4,5,6,7,8,9,0,2,4,6,8,1,3,5,7,9][d+((e=!e)?0:10)]);
}
,0
) % 10 == 0
);
}
function luhnValid4(cardNo) { // cardNo as a string w/ digits only
var s = 0, e = false, p = cardNo.length; while (p > 0) { p--;
s += "01234567890246813579".charAt(cardNo.charAt(p)*1 + ((e=!e)?0:10)) * 1; }
return (s % 10 == 0);
}
function luhnCheck(value) {
return 0 === (value.replace(/\D/g, '').split('').reverse().map(function(d, i) {
return +['0123456789','0246813579'][i % 2][+d];
}).reduce(function(p, n) {
return p + n;
}) % 10);
}
function luhnCheck(value) {
return !(value.replace(/\D/g, '').split('').reverse().reduce(function(a, d, i) {
return a + d * (i % 2 ? 2.2 : 1) | 0;
}, 0) % 10);
}
function luhn(digits) {
return /^\d+$/.test(digits) && !(digits.split("").reverse().map(function(checkDigit, i) {
checkDigit = parseInt(checkDigit, 10);
return i % 2 == 0
? checkDigit
: (checkDigit *= 2) > 9 ? checkDigit - 9 : checkDigit;
}).reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}) % 10);
}
<script>
// takes the form field value and returns true on valid number
function valid_credit_card(value) {
// accept only digits, dashes or spaces
if (/[^0-9-\s]+/.test(value)) return false;
// The Luhn Algorithm. It's so pretty.
var nCheck = 0, nDigit = 0, bEven = false;
value = value.replace(/\D/g, "");
for (var n = value.length - 1; n >= 0; n--) {
var cDigit = value.charAt(n),
nDigit = parseInt(cDigit, 10);
if (bEven) {
if ((nDigit *= 2) > 9) nDigit -= 9;
}
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) == 0;
}
console.log(valid_credit_card("5610591081018250"),"valid_credit_card Validation");
</script>
const LuhnCheckCard = (number) => {
if (/[^0-9-\s]+/.test(number) || number.length === 0)
return false;
return ((number.split("").map(Number).reduce((prev, digit, i) => {
(!(( i & 1 ) ^ number.length)) && (digit *= 2);
(digit > 9) && (digit -= 9);
return prev + digit;
}, 0) % 10) === 0);
}
console.log(LuhnCheckCard("4532015112830366")); // true
console.log(LuhnCheckCard("gdsgdsgdsg")); // false
function valid(number){
var splitNumber = parseInt(number.toString().split(""));
var totalEvenValue = 0;
var totalOddValue = 0;
for(var i = 0; i < splitNumber.length; i++){
if(i % 2 === 0){
if(splitNumber[i] * 2 >= 10){
totalEvenValue += splitNumber[i] * 2 - 9;
} else {
totalEvenValue += splitNumber[i] * 2;
}
}else {
totalOddValue += splitNumber[i];
}
}
return ((totalEvenValue + totalOddValue) %10 === 0)
}
console.log(valid(41111111111111111));
def validate_credit_card_number(card_number):
if(len(str(card_number))==16):
group1 = []
group1_double = []
after_group_double = []
group1_sum = 0
group2_sum = 0
group2 = []
total_final_sum = 0
s = str(card_number)
list1 = [int(i) for i in list(s)]
for i in range(14, -1, -2):
group1.append(list1[i])
for x in group1:
b = 0
b = x * 2
group1_double.append(b)
for j in group1_double:
if(j > 9):
sum_of_digits = 0
alias = str(j)
temp1 = alias[0]
temp2 = alias[1]
sum_of_digits = int(temp1) + int(temp2)
after_group_double.append(sum_of_digits)
else:
after_group_double.append(j)
for i in after_group_double:
group1_sum += i
for i in range(15, -1, -2):
group2.append(list1[i])
for i in group2:
group2_sum += i
total_final_sum = group1_sum + group2_sum
if(total_final_sum%10==0):
return True
else:
return False
card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007
result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")