现在的网站、应用、APP只要用到用户信息,尤其是涉及到订票啊,付费之类的,都会让用户填写身份证号码,而关于身份证号码的校验工作,应该说校验程度比较高的就是四要素检测了,银行卡、身份证号码、手机号、姓名去做指定的API进行校验,一般都是付费的。
比如聚合API最便宜的是0.3元/次,管你校验通过不通过反正一次3毛钱。
还有上传身份证照片,使用图形识别技术识别出来进行校验。
当然,有的是费人工去检查对不对。
或者其他合作校验方式就各家归各家了。
只要没有去做付费四要素检测的话,剩下的就只能自己来检查是否有效了。简单的校验就只是校验位数,15位一代身份证,18位二代身份证。不过现在一代应该是很少了,本文只讨论二代身份证校验了。
身份证号码的组成
公民身份号码是特征组合码,排列顺序从左至右依次为:六位地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
地址码
地址码是常住户口所在县(县级市、旗、区)的行政区划代码,按GB/T2260的规定执行。更详细规则如下:
第一、二位表示省(自治区、直辖市、特别行政区)。
华北地区: 北京市|11,天津市|12,河北省|13,山西省|14,内蒙古自治区|15
东北地区: 辽宁省|21,吉林省|22,黑龙江省|23
华东地区: 上海市|31,江苏省|32,浙江省|33,安徽省|34,福建省|35,江西省|36,山东省|37
华中地区华南地区: 河南省|41,湖北省|42,湖南省|43, 广东省 |44,广西壮族自治区|45,海南省|46
西南地区: 四川省|51,贵州省|52,云南省|53,西藏自治区|54,重庆市|50
西北地区: 陕西省|61,甘肃省|62,青海省|63,宁夏回族自治区|64,新疆维吾尔自治区|65
台湾地区: 台湾省|71 (886) (应该属于华东地区)
港澳地区: 香港特别行政区|81(852) 澳门特别行政区|82 (853) (应该属于华南地区)
第三、四位表示市(地级市、自治州、地区、盟及直辖市所属区和县的汇总码)。其中,01-20,51-70表示地级市;21-50表示地区(自治州、盟)。
第五、六位表示县(区、县级市、旗)。01-18表示地级市、自治州、地区、盟辖县级市;21-80表示县(旗);81-99表示省直辖县级行政单位。
生日期码
顺序码
校验码
校验码计算方法
es6的身份证校验函数
下面使用es6做的基于校验码简单的判断。想要更深层次的还可以对地址码和生日码都进行校验。
const idCardCheck6 = function(card){ if(!card || card.length != 18){ return false } let cards = card.toString().split('') let sign = (12 - cards.reduce((total,value,index)=>{ return total + (index === 17 ? 0 : Math.pow(2,17-index) % 11 * value) },0) % 11 ) % 11 sign = sign === 10 ? 'x' : sign console.log(sign) return cards[17] == sign }
身份信息模拟数据
做开发或者做测试的时候,模拟数据的生成也是很必要的,不然每次都录入“111”,“222”,“测试”,“测试不要动”……的数据,看着界面实在是影响心情,尤其是强迫症还着。这时候,就可以根据身份证生成规则来生成个人信息了。包含姓名,电话,性别,身份证号码,生日,籍贯的生成了。
身份证号码模拟
身份号码模拟就是前面的地区前两位按照地区来模拟,中间四位暂时就纯随机了,有兴趣的话可以去差所有的区县标准数据了,生日码的话就按照现在时间的前一百年间的随机生日,当然也可以自行设置,3位顺序码也随机,纯随机,校验码根据前面随机生成的数据生成,然后组合就是了,注意输出的是字符串,数字的话会造成超出范围的数字类型错误显示的。
下面是简单的生成代码,讲身份信息做成对象来进行输出
const randomPerson = function(){ let areas = { 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:"澳门特别行政区" } let areaIds = Object.keys(areas) let areasId = areaIds[Math.floor(Math.random()*areaIds.length)] let areaCode = Math.floor(Math.random() * 9999) let birthday = new Date(new Date().getTime() - Math.random() * 1000 * 60 * 60 * 24 * 365 * 100) let year = birthday.getFullYear() let month = birthday.getMonth() > 8 ? birthday.getMonth()+1 : "0" + (birthday.getMonth()+1) let day = birthday.getDate() > 9 ? birthday.getDate() : "0" + birthday.getDate() let seqCode = Math.floor(Math.random() * 999) let firstCard = areasId + areaCode + year + month + day + seqCode let sign = (12 - firstCard.split('').reduce((total,value,index)=>{ return total + (index === 17 ? 0 : Math.pow(2,17-index) % 11 * value) },0) % 11 ) % 11 sign = sign === 10 ? 'x' : sign return { area:areas[areasId], birthday:year + "-" + month + "-" + day, sex: seqCode % 2 === 1 ? "男":"女", idCard:firstCard + sign, age: new Date().getFullYear() - year } }
对应生成的数据格式是这样的
{area: "香港特别行政区", birthday: "1982-11-05", sex: "女", idCard: "81463419821105826x", age: 37}
姓名生成
const randomName = function(){ let first = "李王张刘陈杨赵黄周吴徐孙胡朱高林何郭马罗梁宋郑谢韩唐冯于董萧程曹袁邓许傅沈曾彭吕苏卢蒋蔡贾丁魏薛叶阎余潘杜戴夏钟汪田任姜范方石姚谭廖邹熊金陆郝孔白崔康毛邱秦江史顾侯邵孟龙万段漕钱汤尹黎易常武乔贺赖龚文" let last = "英梅华兰珍芳伟军丽敏荣勇静燕娟婷强云杰平超红艳磊丹萍霞斌波玲涛明峰浩飞辉俊鑫鹏林慧颖洋国刚莉倩娜龙亮琴凯帅雪琳晶阳博兵洁芝宇宁健建岩帆瑞花佳香欢欣莹坤利旭文雷彬柳晨凤璐瑜畅玉想楠东杨成" let randomTxt = function(str){ return str.charAt(Math.random()*str.length) } return randomTxt(first) + randomTxt(last) + (Math.random() > 0.3 ? randomTxt(last) : "") }
手机号码生成
这个就简单一点,11位生成,目前的号段如下,更新潮的不追赶了,模拟嘛,前面取号段,后面号码随机,一拼结束。
移动号段:134 135 136 137 138 139 147 148 150 151 152 157 158 159 165 172 178 182 183 184 187 188 198
联通号段:130 131 132 145 146 155 156 166 171 175 176 185 186
电信号段:133 149 153 173 174 177 180 181 189 191 199
虚拟运营商: 170
let randomPhone = function(){ const head = [134,135,136,137,138,139,147,148,150,151,152,157,158,159 ,165,172,178,182,183,184,187,188,198,130,131,132,145,146,155,156,166,171,175,176,185,186,133,149,153,173,174,177,180,181,189,191,199,170] let cont = "" for(let i = 0; i<8; i++){ cont += Math.floor(Math.random()*10) } return head[Math.floor(Math.random()*head.length)] + cont }