tl;dr 一道有点趣味的题,实现方式是 C 语言。输入信用卡卡号检验号码的有效性和发卡银行。 程序需要验证信用卡卡号时,使用 Luhn 算法进行检验。然后通过检验前两位数字和卡号长度,推断发卡行。 暂时在此记录一下。
Luhn 算法 背景 Luhn 算法,也称模10算法,IBM 科学家 Hans Peter Luhn 早在 1954 年 就申请了该算法的专利。 Luhn 算法尽管不是一种安全的加密哈希函数,但在防止意外出错而不是恶意攻击方面的验证还是非常广泛的。
验证过程
卡号中偶数位数字 乘以2,计算数字位的和。注意偶数位乘2后如果是两位数,则拆成十位和个位相加
奇数位数字相加得到和
奇数位和,与偶数位和相加
检验总和是否能被 10 整除,不能则验证无效
检验发卡行 AMEX:15位+34/37 MasterCard:16位+51~55 Visa:13位或16位+4 其他规则与之类似,只要继续按照发卡行编码规则添加验证即可。
在程序中需要对前两位数字和卡号长度进行追踪。
实现中的注意点
C语言实现,已经规定了输入,所以卡号需要用 longlong 存储
C 没有 python 中的len(), 但有strlen()。考虑将输入转换成字符串进行处理。
奇数位与偶数位的计算处理
检验结果和发卡行结果输出,需要注意所有情况。
Code Solution [credit.c] [] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 long long card_num = -1 ; do { card_num = get_long_long("Number: " ); } while (card_num < 0 ); char buf[20 ]; sprintf (buf, "%lld" , card_num); int len = (int )strlen (buf); int sum_single = 0 ; int dou = 0 ; int sum_double = 0 ; int sum_total = 0 ; for (int i = len - 1 ; i > 0 ; i -= 2 ) { sum_single += buf[i] - '0' ; dou = (buf[i - 1 ] - '0' ) * 2 ; if (dou < 10 ) { sum_double += dou; } else { sum_double += (dou / 10 ) + (dou % 10 ); } } if (len % 2 != 0 ) { sum_single += buf[0 ] - '0' ; } sum_total = sum_double + sum_single; if (sum_total % 10 != 0 ) { printf ("INVALID\n" ); } else { if (buf[0 ] == '4' && (len == 13 || len == 16 )) { printf ("VISA\n" ); } else { if ((buf[0 ] == '3' ) && (buf[1 ] == '4' || buf[1 ] == '7' ) && (len == 15 )) { printf ("AMEX\n" ); } else { if ((buf[0 ] == '5' ) && (len == 16 ) && (buf[1 ] == '1' || buf[1 ] == '2' || buf[1 ] == '3' || buf[1 ] == '4' || buf[1 ] == '5' )) { printf ("MASTERCARD\n" ); } else { printf ("INVALID\n" ); } } } }
Test Paypal 提供了一些可供验证的数据 link:https://developer.paypal.com/docs/classic/payflow/payflow-pro/payflow-pro-testing/#credit-card-numbers-for-testing
1 2 3 4 5 6 7 8 9 10 11 12 13 :) identifies 378282246310005 as AMEX :) identifies 371449635398431 as AMEX :) identifies 5555555555554444 as MASTERCARD :) identifies 5105105105105100 as MASTERCARD :) identifies 4111111111111111 as VISA :) identifies 4012888888881881 as VISA :) identifies 1234567890 as INVALID :) identifies 369421438430814 as INVALID :) identifies 4062901840 as INVALID :) identifies 5673598276138003 as INVALID :) identifies 4111111111111113 as INVALID :) rejects a non-numeric input of "foo" :) rejects a non-numeric input of ""