Luhn是著名的校验和算法也叫模10算法,主要应用于解决银行卡号,社保号等重要信息传输出错问题。
先来解释下算法原理,校验和类型的算法,一般是ID+校验号,校验号和ID号的每位相关,如果出错,通过某种运算能检测出这种改动。借用维基百科的例子我来解释下。
我们以数字“7992739871”为例,计算其校验位:
- 从校验位开始,从右往左,偶数位乘2(例如,7*2=14),然后将两位数字的个位与十位相加(例如,10:1+0=1,14:1+4=5);
- 把得到的数字加在一起(本例中得到67);
- 将数字的和取模10(本例中得到7),再用10去减(本例中得到3),得到校验位。
原始数字 | 7 | 9 | 9 | 2 | 7 | 3 | 9 | 8 | 7 | 1 | x |
---|---|---|---|---|---|---|---|---|---|---|---|
偶数位乘2 | 7 | 18 | 9 | 4 | 7 | 6 | 9 | 16 | 7 | 2 | x |
将数字相加 | 7 | 9 | 9 | 4 | 7 | 6 | 9 | 7 | 7 | 2 | =67 |
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;
}
}