start
- 最近番茄学习前端八股文,学的有些乏味了。随即在应用商店下载了几个小游戏,准备把玩放松一下。
- 众所周知,现在玩游戏都是要身份证实名认证的,但是我又有精神洁癖,不想把自己的身份证提供给这种小作坊。
- "输入"一个身份证号码?番茄尝试了很多次,但是它的表单校验却一直无法通过。我很好奇!它这校验咋写的,走我们手撕一个去。
目标
- 了解身份证号码的规则
- 编写正则
研究一下身份证号码的格式
- 我们的身份证号码是长度为18的字符串,除了最后一位可能为字母
x
或0-9
数字,其他每一位都由0-9
数字组成。 - 每一位数字的意义:
1、省份
前1、2位数字表示:所在省份的代码。
2、城市
第3、4位数字表示:所在城市的代码。
3、区县
第5、6位数字表示:所在区县的代码。
4、出生日期
第7~14位数字表示:出生年、月、日。
5、顺序码
第15、16、17位数字表示 ,顺序码奇数表示男性,偶数表示女性
6、校检码
第18位数字是校检码:用来检验身份证的正确性。校检码可以是0~10的数字,10用x表示。校验码是根据前面17位数字根据计算规则得出来的数字(具体的计算规则后面会说到)
说句题外话
- 按照上述的规则,一个刚出生孩子,其实他的身份证账号的绝大部分都是固定的。比如省市县,比如出生日期,比如说校验码。
- 又考虑到每个人的身份证号码是唯一的,所以除去出生地的问题,除去性别的问题,所以一个县一天最多只能出生500个男孩或者500个女孩。
- 那假如一个县同一天内出生的男孩/女孩数量超过的500怎么办?那不是身份证号码不唯一了?
有人简略推算过,发生这种情况的概率暂时比较低,如果真的有一天,一个县一天内出生的孩子超过1000,可以人为的将生日往后推迟一天,当然这只是我的猜测。
编写正则
1.简单的身份证校验
var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
2.进一步限制
// 校验最基本的位数规则,以及校验`校验码`
var checkCode = function (val) {
var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
var code = val.substring(17);
if (p.test(val)) {
var sum = 0;
for (var i = 0; i < 17; i++) {
sum += val[i] * factor[i];
}
if (parity[sum % 11] == code.toUpperCase()) {
return true;
}
}
return false;
}
// 校验年月日
var checkDate = function (val) {
var pattern = /^(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)$/;
if (pattern.test(val)) {
var year = val.substring(0, 4);
var month = val.substring(4, 6);
var date = val.substring(6, 8);
var date2 = new Date(year + "-" + month + "-" + date);
if (date2 && date2.getMonth() == (parseInt(month) - 1)) {
return true;
}
}
return false;
}
// 校验省份编码
var checkProv = function (val) {
var pattern = /^[1-9][0-9]/;
var provs = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江 ", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北 ", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏 ", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门" };
if (pattern.test(val)) {
if (provs[val]) {
return true;
}
}
return false;
}
var checkID = function (val) {
if (checkCode(val)) {
var date = val.substring(6, 14);
if (checkDate(date)) {
if (checkProv(val.substring(0, 2))) {
return true;
}
}
}
return false;
}
校验码生成规则?
// 获取校验码 (这里为了方便演示,就单独把这逻辑抽离出来了,暂不考虑参数的异常情况,建议先正则匹配完基本字段结构再做校验码校验)
function getCheckCode(val) {
// 加权因子
let factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
// 校验码
let parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2]
let sum = 0
for (var i = 0; i < 17; i++) {
sum += val[i] * factor[i]
}
// 校验码校验规则: (前17项每一项 * 对应位数的加权因子) 累加,除以11求余,再对应校验码数组的索引。
return parity[sum % 11]
}
console.log('测试数据', getCheckCode('13082119660231557')) //'测试数据' 1
参考文章:
end
- 所以在
研究一下身份证号码的格式
章节截图的身份证账号的校验码应该为1
,相信这样的身份证号码,妥妥的可以通过前端页面校验了。ღ( ´・ᴗ・` ) - 在我生成合格的身份证账号后,打开小作坊的游戏,输入身份证号码,点击提交,它提示我,姓名和身份证账号不一致。。。。。
- o(╥﹏╥)o哭晕在厕所,拜拜了你嘞。不玩了,学前端去。