最近参加一些招聘,很多时候时候身份证号都会作为表单的一部分,需要用户进行填写。有些表单在填写了身份证号之后,还需要用户手动填写籍贯、性别、出生年月、以及年龄等信息,其实这些信息都在身份证号里面包含了。
身份证号的组成
要验证和解析身份证号,首先应该知道身份证号的组成。
省 市 区 | 年 月 日 | 序列号 | 校验位 |
---|---|---|---|
XX XX XX | XXXXX XX XX | XXX | X |
身份证号可以划分成4部分,分别对应地区、出生年月、序列号、校验位。
- 第1-6位,对应具体到区(县)的地址,一般能够对生源地、籍贯等信息。
区号与地区名的对照关系,有相关的类库可以进行对比。
https://github.com/qianshou/district/blob/master/district-simple.sql - 第7-14位,对应YYYY-mm-dd格式的出生年月。
- 第15-17位,对应顺序码,该地区同年同月同日生的人的编号,男性都是奇数,女性都是偶数。
- 第18位位校验位,对前面17为数字进行校验,检查身份证号的正确性。
具体的校验规则如下:
身份证号的前17位数,分别乘以规定参数,然后累计和除以11,得到的余数通过映射表进而得到校验位的值。
乘数参数表
7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2
余数映射表
余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
校验位 | 1 | 0 | X | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
身份证号的验证
身份证号的验证,可以分为正则表达式的匹配验证和校验位的验证两部分。
由于身份证号的验证,在前端用的比较多,下面给出javascript的实现。
function checkIDNumber(id) {
//兼容最后一位X大小写
id = id.toUpperCase();
//正则检查
if(! /^[1-3]\d{16}[\d,X]$/.test(id)){
return false;
}
//校验位检查
var vcode = id[id.length-1];
var params = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];
var map = ['1','0','X','9','8','7','6','5','4','3','2'];
var sum = 0;
for(var i=0;i<params.length;i++){
sum += id[i]*params[i];
}
var remainder = sum%11;
if(vcode == map[remainder]){
return true;
}else{
return false;
}
}
身份证号的解析
在函数checkIDNumber的基础上进行修改,实现身份证号的检查与解析。
var district_map = require('./district-simple.json');
function parseIDNumber(id) {
//兼容最后一位X大小写
id = id.toUpperCase();
//正则检查,并获取相关信息
var data = /^([1-3]\d{5})(\d{8})(\d{3})([\d,X])$/.exec(id);
if(!data){
return false;
}
//校验位检查
var vcode = id[id.length-1];
var params = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];
var map = ['1','0','X','9','8','7','6','5','4','3','2'];
var sum = 0;
for(var i=0;i<params.length;i++){
sum += id[i]*params[i];
}
var remainder = sum%11;
if(vcode != map[remainder]){
return false;
}
var ret = [];
//获取地区信息
var district = [];
var discode = data[1];
var provcode = discode.substring(0,2)+'0000';
var citycode = discode.substring(0,4)+'00';
if(typeof district_map[provcode] != "undefined"){
district.push(district_map[provcode])
}
if(typeof district_map[citycode] != "undefined"){
district.push(district_map[citycode]);
}
if(typeof district_map[provcode] != "undefined"){
district.push(district_map[discode]);
}
ret['district'] = district;
//获取出生日期
var birth_date = data[2];
var year = parseInt(birth_date.substring(0,4));
var month = parseInt(birth_date.substring(4,6));
var day = parseInt(birth_date.substring(6,8));
var birth = [year,month,day];
ret['birth'] = birth;
//获取年龄
var date = new Date();
var year_diff = date.getFullYear()-year;
var month_diff = date.getMonth()+1-month;
var day_diff = date.getDate()-day;
var age = year_diff;
if(month_diff<0 || (month_diff==0&&day_diff<0)){
age--;
}
ret['age'] = age;
//获取性别信息
var serno = data[3];
var sex = serno%2;
ret['sex'] = sex;
return ret;
}
为了方便调用,我将sql语句中的区号和名称的对应关系,生成了相关的json文件。在该函数的实现中,为了方便调用,采用了node.js的引入机制使用的json文件,如果在前端JavaScript调用时,可以采用ajax请求引入json文件信息,然后进行匹配。
https://github.com/qianshou/district/blob/master/district-simple.json