引言
在金融類軟件開發(fā)過程中薇溃,經(jīng)常會涉及到用戶銀行卡信息的校驗(yàn),包括銀行卡卡號缭乘、開戶人姓名痊焊、身份證號和手機(jī)號等。理想狀況下忿峻,當(dāng)然希望能夠?qū)⑦@些信息傳遞給服務(wù)器薄啥,然后服務(wù)器通過銀行或其他機(jī)構(gòu)提供的API進(jìn)行匹配性的驗(yàn)證。但是逛尚,如果服務(wù)器沒有這些可供驗(yàn)證的API垄惧,就只能在APP端進(jìn)行一個(gè)格式上的校驗(yàn)了。
身份證號可以用16位或18位的數(shù)字和字母組成的正則表達(dá)式驗(yàn)證格式绰寞,手機(jī)號可以用11位的數(shù)字驗(yàn)證到逊,而對于銀行卡卡號就相對比較麻煩了,涉及到下面闡述的Luhn算法規(guī)則滤钱。
Luhn簡介
Luhn算法/公式觉壶,也稱“模10算法”,是一種簡單的校驗(yàn)公式件缸,常被用于銀行卡卡號铜靶、IMEI號等證件號碼的識別校驗(yàn)。Luhn算法是由IBM的一位科學(xué)家所創(chuàng)他炊,之后被ISO指定争剿,成為大家公認(rèn)的一項(xiàng)標(biāo)準(zhǔn)。
注意一點(diǎn)痊末,Luhn算法存在的目的并不是成為一種加密安全的哈希函數(shù)蚕苇。它的目的在于防止意外操作導(dǎo)致的錯(cuò)誤,如錯(cuò)誤輸入凿叠,而不是惡意攻擊涩笤。很多銀行卡卡號和政府證件號碼將該算法作為一種簡單的方式用于從鍵盤錯(cuò)誤錄入或其他錯(cuò)誤號碼中分辨有效數(shù)字。
校驗(yàn)規(guī)則
Luhn算法被用于最后一位為校驗(yàn)碼的一串?dāng)?shù)字的校驗(yàn)盒件,通過如下規(guī)則計(jì)算校驗(yàn)碼的正確性:
按照從右往左的順序蹬碧,從這串?dāng)?shù)字的右邊開始,包含校驗(yàn)碼履恩,將偶數(shù)位數(shù)字乘以2锰茉,如果每次乘二操作的結(jié)果大于9(如 8 × 2 = 16),然后計(jì)算個(gè)位和十位數(shù)字的和(如 1 + 6 = 7)或者用這個(gè)結(jié)果減去9(如 16 - 9 = 7)切心;
第一步操作過后會得到新的一串?dāng)?shù)字飒筑,計(jì)算所有數(shù)字的和(包含校驗(yàn)碼)片吊;
用第二步操作得到的和進(jìn)行“模10”運(yùn)算,如果結(jié)果位0协屡,表示校驗(yàn)通過俏脊,否則失敗。
下面肤晓,我們通過具體的例子來說明上述規(guī)則爷贫,給定一串?dāng)?shù)字:7992739871x,注意补憾,末尾的x表示校驗(yàn)碼漫萄,按照上面的規(guī)則進(jìn)行計(jì)算,如圖:
按照規(guī)則計(jì)算新數(shù)字串中各位數(shù)字的和:67+x 盈匾,并進(jìn)行“模10”運(yùn)算:(67+x) mod 10 腾务,只有滿足結(jié)果為0的x值才是正確的校驗(yàn)碼。通過如下計(jì)算可以得到x的值:
計(jì)算不包含校驗(yàn)碼的所有數(shù)字的和(67)削饵;
乘以9(603)岩瘦;
最后一位數(shù)字,3窿撬,就是檢驗(yàn)碼启昧,即,x = 3 劈伴。
當(dāng)然密末,你也可以選擇別的計(jì)算方式,或者口算就能得到x為3宰啦,畢竟目的只有一個(gè)苏遥, 路可以有很多條。諸如其他的值赡模,x為{1,2师抄,4漓柑,5,6叨吮,7辆布,8,9茶鉴,0}锋玲,都是錯(cuò)誤的,均不滿足Luhn算法的要求涵叮。
優(yōu)缺點(diǎn)
Luhn算法可以檢測出任何單碼錯(cuò)誤和近乎所有的相鄰數(shù)字交換產(chǎn)生的錯(cuò)誤惭蹂,但是檢測不出兩個(gè)數(shù)字序列09和90的交換錯(cuò)誤伞插。它可以檢測出十分之七比例的相同兩位數(shù)交換錯(cuò)誤(但2 ? 55, 33 ? 66 和 44 ? 77除外)。
Java實(shí)現(xiàn)
通過上面算法介紹和規(guī)則說明盾碗,大家應(yīng)該能夠利用自己所擅長的語言實(shí)現(xiàn)對銀行卡卡號格式的校驗(yàn)了媚污,比如Java語言下的校驗(yàn)實(shí)現(xiàn)代碼為:
/**
* 匹配Luhn算法:可用于檢測銀行卡卡號
* @param cardNo
* @return
*/
public static boolean matchLuhn(String cardNo) {
int[] cardNoArr = new int[cardNo.length()];
for (int i=0; i<cardNo.length(); i++) {
cardNoArr[i] = Integer.valueOf(String.valueOf(cardNo.charAt(i)));
}
for(int i=cardNoArr.length-2;i>=0;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];
}
return sum % 10 == 0;
}
利用Luhn算法的規(guī)則也可以寫出隨機(jī)生成一個(gè)滿足條件的銀行卡卡號的實(shí)現(xiàn)代碼。
Luhn算法英文參考:
https://en.wikipedia.org/wiki/Luhn_algorithm#cite_note-0