一、背景介绍
前两天测试小姐姐突然找到我,说我的表单校验是不是有问题,为什么一个格式很标准的身份证号校验总是提示校验失败呢?能改一下校验吗,不能然每次都要使用她的真实身份证号来测试了...
好吧,最后给她推荐了一个身份证号码生成网站解决了她的困扰。当然,也顺便给我的同事们分享了一波我使用的校验方法,就像接入了公安系统一样可以校验出那些自己编造的身份证号。
二、校验规则介绍
对身份证号生成规则比较熟悉的小伙伴可能已经猜到了,我使用的是ISO 7064:1983.MOD 11-2
校验算法。简单的说就是将18位的身份证号的前17位与对应的加权因子相乘对11取余,然后余数对应的code就应该是身份证号的第18位,获取到的值与第十八位相比如果相等,那就校验通过。
听起来是不是很简单,只要我们任意输入17位数字生成第18位,这个18位数字就能通过以上校验,接下来详细介绍一下校验流程~
1.校验流程
我们以11111111111111111
(17个1)这个数字为例,对这个算法一探究竟。小伙伴们也可以随便你身份证号的前17位一起走一边流程。
(1) 加权因子求和
17 位的加权因子分别是 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
,
1*7 + 1*9 + 1*10 + 1*5 + 1*8 1*4 + 1*2 + 1*1 + 1*6 + 1*3 + 1*7 + 1*9 + 1*10 + 1*5 + 1*8 + 1*4 + 1*2
分别求和得到的结果是100
(2) 对11取余
100 % 11 = 1
(3) 与12差值再对11取余
(12 - 1) % 11 = 0
(4) 验证
验证网站
验证结果如图
2.其他校验
如果身份证号校验只用ISO 7064:1983.MOD 11-2
是不够严谨的,有的读者这可能已经想到了,因为任意一段长度为17的数字加上经过计算的校验码,那前17位数字可能可能都是不符合基本规则的,比如错误的日期格式,非法的地址码等等。
这里注意一点,长度为18的数字已经超出了js数值的计算范围,所以校验时可以转化为数组或者字符串。更详细的规则如下:
- 第一位不可能是0
- 第二位到第六位可以是0-9
- 第七位到第十位是年份,所以七八位为19或者20
- 十一位和十二位是月份,这两位是01-12之间的数值
- 十三位和十四位是日期,是从01-31之间的数值
- 十五,十六,十七都是数字0-9
- 十八位可能是数字0-9,也可能是X
身份证号的的详细规则请看文末的总结。
三、代码
包含上方提到的两种校验。
function checkIDCard (idcode) {
// 加权因子
const weightFactor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
// 校验码
const checkCode = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
const code = String(idcode)
const last = idcode[17]// 最后一位
const seventeen = code.substring(0, 17)
// ISO 7064:1983.MOD 11-2 判断最后一位校验码是否正确
const arr = seventeen.split('')
const len = arr.length
let num = 0
for (let i = 0; i < len; i++) {
num = num + arr[i] * weightFactor[i]
}
// 获取余数
const resisue = num % 11
const lastNo = checkCode[resisue]
// 身份证号格式的正则思路
const idcardPatter = /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/
// 判断格式是否正确
const format = idcardPatter.test(idcode)
// 返回验证结果,校验码和格式同时正确才算是合法的身份证号码
return last === lastNo && format
}
- 代码中使用了一个数组直接转化最后的结果实际与
二、1.(3)
操作的结果是一样的 - 使用该方法传入的参数需要是一个字符串
四、校验优化
注意:以下函数的入参都必须是一个字符串。
1.通过身份证号码获取性别
const cardToSex = idNo => {
idNo = idNo.replace(/\s*/g, '')
let sexStr = ''
if (idNo.length === 15) {
sexStr = parseInt(idNo.substring(14, 1), 10) % 2 ? '男' : '女'
} else if (idNo.length === 18) {
sexStr = parseInt(idNo.substring(17, 1), 10) % 2 ? '男' : '女'
}
return sexStr
}
2.通过身份证号码获取出生年月日
const cardToBirthday = (idNo, split = '-') => {
idNo = idNo.replace(/\s*/g, '')
let tmpStr = ''
if (idNo.length === 15) {
tmpStr = idNo.substring(6, 12)
tmpStr = '19' + tmpStr
tmpStr = tmpStr.substring(0, 4) + split + tmpStr.substring(4, 6) + split + tmpStr.substring(6)
} else if (idNo.length === 18) {
tmpStr = idNo.substring(6, 14)
tmpStr = tmpStr.substring(0, 4) + split + tmpStr.substring(4, 6) + split + tmpStr.substring(6)
}
return tmpStr
}
五、身份证号编码规则
位数 | 含义 | 1~2 | 所在省(直辖市、自治区)的代码 | 3~4 | 所在地级市(自治州)的代码 | 5~6 | 所在区(县、自治县、县级市)的代码 | 7~10 | 出生年份 | 11~12 | 出生月份 | 13~14 | 出生日 | 15~16 | 所在派出所代码 | 17 | 奇数代表男性,偶数代表女性 | 18 | 校验码,生成规则参考上方的ISO 7064:1983.MOD 11-2 算法 |
---|
前六位详细地址代码可以参考这里。
END
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!