Luhn是著名的校验和算法也叫模10算法,主要应用于解决银行卡号,社保号等重要信息传输出错问题。
先来解释下算法原理,校验和类型的算法,一般是ID+校验号,校验号和ID号的每位相关,如果出错,通过某种运算能检测出这种改动。借用维基百科的例子我来解释下。
我们以数字“7992739871”为例,计算其校验位:
- 从校验位开始,从右往左,偶数位乘2(例如,7*2=14),然后将两位数字的个位与十位相加(例如,10:1+0=1,14:1+4=5);
- 把得到的数字加在一起(本例中得到67);
- 将数字的和取模10(本例中得到7),再用10去减(本例中得到3),得到校验位。
原始数字 偶数位乘2 将数字相加
7 | 9 | 9 | 2 | 7 | 3 | 9 | 8 | 7 | 1 | x |
7 | 18 | 9 | 4 | 7 | 6 | 9 | 16 | 7 | 2 | x |
7 | 9 | 9 | 4 | 7 | 6 | 9 | 7 | 7 | 2 | =6 7 |
OK,解释到这里,那么跟我们有什么相关呢,最常见的例子就是银行卡号,我们的银行卡号其实最后一位都是由该算法得出的校验码,校验码不用我们算了,我们只要从低位向高位(包括校验和),偶数位做上述转化,然后每位加在一起,必然满足%10==0,否则校验失败,下面是我实现的Luhn类,主要功能是校验和生成校验码。
public class Luhn { private int[] no; private Boolean isValidate = null; public Luhn(String strno) { this(convertStrToInArr(strno)); } public Luhn(int[] no) { if(null!=no && no.length>0) { this.no = Arrays.copyOf(no, no.length); for(int i=0;i<no.length;i++) { if(no[i]<0) { throw new IllegalArgumentException("No can not contain negtive value"); } } }else{ throw new IllegalArgumentException("No is null or Empty"); } } /** * 校验 * @return */ public boolean check() { if(null == isValidate) { isValidate = luhnCheck(getCardNoArr()); } return isValidate; } /** * 获取全部id * @return */ public int[] getCardNoArr() { return Arrays.copyOf(no, no.length); } /** * 计算校验和的算法 * @return */ public int getCheckSum(){ if(check()) { return no[0]; } int[] cardNoArr = getCardNoArr(); for(int i=0;i<cardNoArr.length;i+=2) { cardNoArr[i] <<= 1; cardNoArr[i] = cardNoArr[i]/10 + cardNoArr[i]%10; } int sum = 0; for(int i=0;i<cardNoArr.length;i++) { sum += cardNoArr[i]; //System.out.print(cardNoArr[i]); } return sum * 9 % 10; } private static int[] convertStrToInArr(String cardNo) { if(null==cardNo)throw new IllegalArgumentException(); int index = cardNo.length(); int[] cardNoArr = new int[cardNo.length()]; for(char c : cardNo.toCharArray()) { cardNoArr[--index] = c - '0'; } return cardNoArr; } /** * 校验的具体算法实现 * @param cardNoArr * @return */ private static boolean luhnCheck(int[] cardNoArr) { for(int i=1;i<cardNoArr.length;i+=2) { cardNoArr[i] <<= 1; cardNoArr[i] = cardNoArr[i]/10 + cardNoArr[i]%10; } int sum = 0; for(int i=0;i<cardNoArr.length;i++) { sum += cardNoArr[i]; //System.out.print(cardNoArr[i]); } return sum % 10 == 0; } }