- 大多数银行卡为16位或19位,所以只支持16位或19位的银行卡
- 最后一位是校验位,银行卡校验规则基于Luhn算法
- 以卡号6212280200141664948为例
- 校验过程为:
- 去掉校验位 8,得621228020014166494
- 卡号倒数偶数位相加,即 9 + 6 + 1 + 1 + 0 + 0 + 2 + 1 + 6 = 26
- 卡号倒数奇数位分别乘以2,即 4、4、6、4、0、2、8、2、2分别乘以2,
得 8、8、12、8、0、4、16、4、4 - 奇数位乘以2得到的如果是两位数,则个位和十位相加(或两位数减去9),否则不变,例如 12 -> 1 + 2, 16-> 16 - 9,分别得到 8、8、3、8、0、4、7、4、4
- 将奇数位的计算结果相加, 即 8 + 8 + 3 + 8 + 0 + 4 + 7 + 4 + 4 = 46
- 将偶数位的计算结果与奇数位的计算结果相加,即 26 + 46 = 72
- 计算结果乘以10,取模得 72 mod 10 = 2
- 如果模为0,则校验位为0,否则校验位为2的补位,即 10 - 2 = 8
Java算法
package com.xxx.demo.common.util;
import java.util.regex.Pattern;
public final class AcctIdUtils {
private static final Pattern acctCheckPattern = Pattern.compile("^(?:\\d{16}|\\d{19})$");
private static final Pattern acctCreatePattern = Pattern.compile("^(?:\\d{15,16}|\\d{18,19})$");
private AcctIdUtils () {}
public static boolean checkAcctId(String acctId) {
if (acctId == null || !acctCheckPattern.matcher(acctId).matches()) {
return false;
}
return acctId.equals(createAcctId(acctId));
}
public static String createAcctId(String acctId) {
if (acctId == null || !acctCreatePattern.matcher(acctId).matches()) {
return "";
}
int sum = 0;
int lastIndex = acctId.length() < 17 ? 14 : 17;
String preAcctId = acctId.substring(0, lastIndex + 1);
for (int i = 0; i <= lastIndex; i++) {
int unit = acctId.charAt(lastIndex - i) - '0';
if ((i & 1) == 0) {
if (unit < 5) {
sum += unit * 2;
} else {
sum += unit * 2 - 9;
}
} else {
sum += unit;
}
}
int remainder = sum % 10;
int checkCode = remainder == 0 ? 0 : 10 - remainder;
return preAcctId + checkCode;
}
}
JavaScript算法
(function (window) {
var createAcctId = function (acctId) {
if (!acctId || !/^(?:\d{15,16}|\d{18,19})$/g.test(acctId)) {
return '';
}
acctId = '' + acctId;
var sum = 0;
var lastIndex = acctId.length < 17 ? 14 : 17;
var preAcctId = acctId.substring(0, lastIndex + 1);
for (var i = 0; i <= lastIndex; i++) {
var unit = acctId.charAt(lastIndex - i) - '0';
if ((i & 1) === 0) {
if (unit < 5) {
sum += unit * 2;
} else {
sum += unit * 2 - 9;
}
} else {
sum += unit;
}
}
var remainder = sum % 10;
var checkCode = remainder === 0 ? 0 : 10 - remainder;
return preAcctId + checkCode;
};
var checkAcctId = function (acctId) {
if (!acctId || !/^(?:\d{16}|\d{19})$/g.test(acctId)) {
return false;
}
acctId = '' + acctId;
return acctId === createAcctId(acctId);
};
window.checkAcctId = checkAcctId;
window.createAcctId = createAcctId;
})(window);