【敏感数据识别】银行卡号校验实现(准确率高)

一、常见银行卡号校验实现

银行卡号正则:^([4-6]{1})(\d{15}|\d{18})$ + luhm校验位
缺点:易与编号碰撞

二、解决办法

正则 + luhm校验位 + 卡bin + 银行卡长度

银行卡号由发卡行标识(即卡bin)+发卡行自定位+校验位构成,其中卡BIN号(Bank Identification Number)即发卡银行标识代码的英文缩写,为银行卡号前6位,由中国银联负责向机构分配、确认和管理。

中国银行发卡步骤:
1、向银联申请卡bin
2、银联通过
3、银行发卡

三、卡bin获取难点

银联未公开卡bin数据,卡bin文件一月一更新,仅支持企业身份申请卡bin文件。通过申请后,银联会将卡bin文件发送给企业邮箱。
卡bin文件中包含每一卡bin对应发卡行银行卡号长度、卡片类型(借记卡、储蓄卡、信用卡等)、发卡行编码等信息。
所以,卡bin是只能以企业身份拿到的。如果你所在的公司有做支付的团队,那么在企业内部就已经从银联申请过卡bin文件了,找到自己公司的支付团队申请卡bin就行了。

四、代码实现

注:本文不提供卡bin文件,需自行寻找或向银联申请

public class BankCardUtil {
	// bin -> 银行信息
	private static final Map<String, BankCardBinInfo> BIN_TO_INFO_MAP = new HashMap<>();
	// bin -> 银行卡长度
	private static final Map<String, Integer> BIN_TO_LENGTH_MAP = new HashMap<>();

	static {
		InputStream inputStream = null;
		try {
			String path = "static/卡bin文件.xlsx";
			inputStream = BankCardUtil.class.getClassLoader().getResourceAsStream(path);
			ExcelReader reader = ExcelUtil.getReader(inputStream, "sheet1");
			List<List<Object>> readAll = reader.read();
			for (int i = 1; i < readAll.size(); i++) {
				List<Object> row = readAll.get(i);
				String bin = String.valueOf(row.get(1));
				String cardName = String.valueOf(row.get(2));
				Integer panLength = Integer.parseInt(row.get(3) + "");
				String cardType = String.valueOf(row.get(8));
				String cardTypeName = String.valueOf(row.get(9));
				String bankCode = String.valueOf(row.get(10));
				String bankName = String.valueOf(row.get(11));
				String issuingBankName = String.valueOf(row.get(13));
				String issuingBankCode = String.valueOf(row.get(14));
				BankCardBinInfo bankCardBinInfo = new BankCardBinInfo(bin, cardName, panLength, cardType, cardTypeName, bankCode, bankName, "", issuingBankName, issuingBankCode, "", "");
				BIN_TO_INFO_MAP.put(bin, bankCardBinInfo);
				BIN_TO_LENGTH_MAP.put(bin, panLength);
			}
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	//校验银行卡号
	public static boolean checkBankCard(String cardId) {
		if (cardId == null || cardId.length() == 0) {
			return false;
		}
		//1、luhm检验校验位
		char bit = getBankCardCheckCode(cardId.substring(0, cardId.length() - 1));
		if (bit == 'N' || cardId.charAt(cardId.length() - 1) != bit) {
			return false;
		}
		//2、校验bin
		String bin = cardId.substring(0, 6);
		if (!BIN_TO_INFO_MAP.containsKey(bin)) {
			return false;
		}
		//3、校验银行卡长度
		Integer length = BIN_TO_LENGTH_MAP.get(bin);
		if (length == null || cardId.length() != length) {
			return false;
		}
		return true;
	}

	//从不含校验位的银行卡卡号采用 Luhm 校验算法计算校验位
	public static char getBankCardCheckCode(String nonCheckCodeCardId) {
		if (nonCheckCodeCardId == null || nonCheckCodeCardId.trim().length() == 0
			|| !nonCheckCodeCardId.matches("\\d+")) {
			//如果传的不是数据返回N
			return 'N';
		}
		char[] chs = nonCheckCodeCardId.trim().toCharArray();
		int luhmSum = 0;
		for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
			int k = chs[i] - '0';
			if (j % 2 == 0) {
				k *= 2;
				k = k / 10 + k % 10;
			}
			luhmSum += k;
		}
		return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
	}
}

五、参考资料

2020年8月10日发布的银联官方公布的银行卡BIN资料包下载
银联成员机构资格准入审批介绍-机构代码、BIN号及样卡

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
银行卡校验是一个比较常见的需求,可以通过 JavaScript 实现。以下是一个简单的示例代码: ```javascript function checkBankCard(bankno) { if (bankno.length < 16 || bankno.length > 19) { return false; } var num = /^\d*$/; // 全数字正则表达式 if (!num.exec(bankno)) { return false; } // 银行卡校验规则 var strBin = '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,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99'; var lastNum = bankno.substr(bankno.length - 1, 1); var first15Num = bankno.substr(0, bankno.length - 1); var newArr = new Array(); for (var i = first15Num.length - 1; i > -1; i--) { newArr.push(first15Num.substr(i, 1)); } var arrJiShu = new Array(); // 奇数位*2的积 <9 var arrJiShu2 = new Array(); // 奇数位*2的积 >9 var arrOuShu = new Array(); // 偶数位数组 for (var j = 0; j < newArr.length; j++) { if ((j + 1) % 2 == 1) { // 奇数位 if (parseInt(newArr[j]) * 2 < 9) arrJiShu.push(parseInt(newArr[j]) * 2); else arrJiShu2.push(parseInt(newArr[j]) * 2); } else // 偶数位 arrOuShu.push(newArr[j]); } var jishu_child1 = new Array(); // 奇数位*2 >9 的分割之后的数组个位数 var jishu_child2 = new Array(); // 奇数位*2 >9 的分割之后的数组十位数 for (var h = 0; h < arrJiShu2.length; h++) { jishu_child1.push(parseInt(arrJiShu2[h]) % 10); jishu_child2.push(parseInt(arrJiShu2[h]) / 10); } var sumJiShu = 0; // 奇数位*2 < 9 的数组之和 var sumOuShu = 0; // 偶数位数组之和 var sumJiShuChild1 = 0; // 奇数位*2 >9 的分割之后的数组个位数之和 var sumJiShuChild2 = 0; // 奇数位*2 >9 的分割之后的数组十位数之和 var sumTotal = 0; for (var m = 0; m < arrJiShu.length; m++) { sumJiShu = sumJiShu + parseInt(arrJiShu[m]); } for (var n = 0; n < arrOuShu.length; n++) { sumOuShu = sumOuShu + parseInt(arrOuShu[n]); } for (var p = 0; p < jishu_child1.length; p++) { sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]); sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]); } // 计算总和 sumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2); // 计算Luhm值 var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10; var luhm = 10 - k; if (lastNum == luhm && strBin.indexOf(bankno.substring(0, 2)) != -1) { return true; } else { return false; } } ``` 调用示例: ```javascript var bankno = '1234567890123456'; // 银行卡 if (checkBankCard(bankno)) { console.log('银行卡格式正确'); } else { console.log('银行卡格式错误'); } ``` 以上代码中,`checkBankCard` 函数接受一个参数 `bankno`,即需要校验银行卡。函数首先判断银行卡的长度是否符合规范(16~19位),然后使用正则表达式判断银行卡是否全是数字。接着,根据银行卡校验规则对银行卡进行校验,最后计算出 Luhm 值,判断校验结果是否正确。 需要注意的是,以上代码只是一个简单的示例,实际应用中可能需要根据不同的银行卡类型进行不同的校验规则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值