Js实现中国公民身份证号码有效性验证实例代码


Posted in Javascript onMay 03, 2017

本文将使用JavaScript实现中国公民(15位或者18位)身份证号码的相关验证,功能如下:

  1. 身份证号有效性验证
  2. 分析详细身份证信息
  3. 生成一个虚拟的省份证号码。

身份证号码验证

1、号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

2、地址码(前六位数)

表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。

3、出生日期码(第七位至十四位)

表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。

4、顺序码(第十五位至十七位)

表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。

5、校验码(第十八位数)

(1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, … , 16 ,先对前17位数字的权求和

Ai:表示第i位置上的身份证号码数字值

Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

(2)计算模 Y = mod(S, 11)

(3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2

此处将使用一个全国的地址码 GB2260,在下面的下载地址可以看到。

/*
*http://blog.jdk5.com/zh/javascript-chinese-personal-id-card-validation/
*/
function IDValidator() {
 var param = {
 error : {
 longNumber : '长数字存在精度问题,请使用字符串传值! Long number is not allowed, because the precision of the Number In JavaScript.'
 }
 };
 var util = {
 checkArg : function(id) {
 var argType = (typeof id);
 
 switch (argType) {
 case 'number':
 // long number not allowed
 id = id.toString();
 if (id.length > 15) {
 this.error(param.error.longNumber);
 return false;
 }
 break;
 case 'string':
 break;
 default:
 return false;
 }
 id = id.toUpperCase();
 var code = null;
 if (id.length === 18) {
 // 18位
 code = {
 body : id.slice(0, 17),
 checkBit : id.slice(-1),
 type : 18
 };
 } else if (id.length === 15) {
 // 15位
 code = {
 body : id,
 type : 15
 };
 } else {
 return false;
 }
 return code;
 }
 // 地址码检查
 ,
 checkAddr : function(addr, GB2260) {
 var addrInfo = this.getAddrInfo(addr, GB2260);
 return (addrInfo === false ? false : true);
 }
 // 取得地址码信息
 ,
 getAddrInfo : function(addr, GB2260) {
 GB2260 = GB2260 || null;
 // 查询GB/T2260,没有引入GB2260时略过
 if (GB2260 === null) {
 return addr;
 }
 if (!GB2260.hasOwnProperty(addr)) {
 // 考虑标准不全的情况,搜索不到时向上搜索
 var tmpAddr;
 tmpAddr = addr.slice(0, 4) + '00';
 if (!GB2260.hasOwnProperty(tmpAddr)) {
 tmpAddr = addr.slice(0, 2) + '0000';
 if (!GB2260.hasOwnProperty(tmpAddr)) {
 return false;
 } else {
 return GB2260[tmpAddr] + '未知地区';
 }
 } else {
 return GB2260[tmpAddr] + '未知地区';
 }
 } else {
 return GB2260[addr];
 }
 }
 // 生日码检查
 ,
 checkBirth : function(birth) {
 var year, month, day;
 if (birth.length == 8) {
 year = parseInt(birth.slice(0, 4), 10);
 month = parseInt(birth.slice(4, 6), 10);
 day = parseInt(birth.slice(-2), 10);
 } else if (birth.length == 6) {
 year = parseInt('19' + birth.slice(0, 2), 10);
 month = parseInt(birth.slice(2, 4), 10);
 day = parseInt(birth.slice(-2), 10);
 } else {
 return false;
 }
 // TODO 是否需要判断年份
 /*
 * if( year<1800 ){ return false; }
 */
 // TODO 按月份检测
 if (month > 12 || month === 0 || day > 31 || day === 0) {
 return false;
 }
 
 return true;
 }
 // 顺序码检查
 ,
 checkOrder : function(order) {
 // 暂无需检测
 
 return true;
 }
 // 加权
 ,
 weight : function(t) {
 return Math.pow(2, t - 1) % 11;
 }
 // 随机整数
 ,
 rand : function(max, min) {
 min = min || 1;
 return Math.round(Math.random() * (max - min)) + min;
 }
 // 数字补位
 ,
 str_pad : function(str, len, chr, right) {
 str = str.toString();
 len = len || 2;
 chr = chr || '0';
 right = right || false;
 if (str.length >= len) {
 return str;
 } else {
 for (var i = 0, j = len - str.length; i < j; i++) {
 if (right) {
 str = str + chr;
 } else {
 str = chr + str;
 }
 }
 return str;
 }
 }
 // 抛错
 ,
 error : function(msg) {
 var e = new Error();
 e.message = 'IDValidator: ' + msg;
 throw e;
 }
 };
 var _IDValidator = function(GB2260) {
 if (typeof GB2260 !== "undefined") {
 this.GB2260 = GB2260;
 }
 // 建立cache
 this.cache = {};
 };
 _IDValidator.prototype = {
 isValid : function(id) {
 var GB2260 = this.GB2260 || null;
 var code = util.checkArg(id);
 if (code === false) {
 return false;
 }
 // 查询cache
 if (this.cache.hasOwnProperty(id)
 && typeof this.cache[id].valid !== 'undefined') {
 return this.cache[id].valid;
 } else {
 if (!this.cache.hasOwnProperty(id)) {
 this.cache[id] = {};
 }
 }
 
 var addr = code.body.slice(0, 6);
 var birth = (code.type === 18 ? code.body.slice(6, 14) : code.body
 .slice(6, 12));
 var order = code.body.slice(-3);
 
 if (!(util.checkAddr(addr, GB2260) && util.checkBirth(birth) && util
 .checkOrder(order))) {
 this.cache[id].valid = false;
 return false;
 }
 
 // 15位不含校验码,到此已结束
 if (code.type === 15) {
 this.cache[id].valid = true;
 return true;
 }
 
 /* 校验位部分 */
 
 // 位置加权
 var posWeight = [];
 for (var i = 18; i > 1; i--) {
 var wei = util.weight(i);
 posWeight[i] = wei;
 }
 
 // 累加body部分与位置加权的积
 var bodySum = 0;
 var bodyArr = code.body.split('');
 for (var j = 0; j < bodyArr.length; j++) {
 bodySum += (parseInt(bodyArr[j], 10) * posWeight[18 - j]);
 }
 
 // 得出校验码
 var checkBit = 12 - (bodySum % 11);
 if (checkBit == 10) {
 checkBit = 'X';
 } else if (checkBit > 10) {
 checkBit = checkBit % 11;
 }
 checkBit = (typeof checkBit === 'number' ? checkBit.toString()
 : checkBit);
 
 // 检查校验码
 if (checkBit !== code.checkBit) {
 this.cache[id].valid = false;
 return false;
 } else {
 this.cache[id].valid = true;
 return true;
 }
 
 }
 
 // 分析详细信息
 ,
 getInfo : function(id) {
 var GB2260 = this.GB2260 || null;
 // 号码必须有效
 if (this.isValid(id) === false) {
 return false;
 }
 // TODO 复用此部分
 var code = util.checkArg(id);
 
 // 查询cache
 // 到此时通过isValid已经有了cache记录
 if (typeof this.cache[id].info !== 'undefined') {
 return this.cache[id].info;
 }
 
 var addr = code.body.slice(0, 6);
 var birth = (code.type === 18 ? code.body.slice(6, 14) : code.body
 .slice(6, 12));
 var order = code.body.slice(-3);
 
 var info = {};
 info.addrCode = addr;
 if (GB2260 !== null) {
 info.addr = util.getAddrInfo(addr, GB2260);
 }
 info.birth = (code.type === 18 ? (([ birth.slice(0, 4),
 birth.slice(4, 6), birth.slice(-2) ]).join('-')) : ([
 '19' + birth.slice(0, 2), birth.slice(2, 4),
 birth.slice(-2) ]).join('-'));
 info.sex = (order % 2 === 0 ? 0 : 1);
 info.length = code.type;
 if (code.type === 18) {
 info.checkBit = code.checkBit;
 }
 
 // 记录cache
 this.cache[id].info = info;
 
 return info;
 }
 
 // 仿造一个号
 ,
 makeID : function(isFifteen) {
 var GB2260 = this.GB2260 || null;
 
 // 地址码
 var addr = null;
 if (GB2260 !== null) {
 var loopCnt = 0;
 while (addr === null) {
 // 防止死循环
 if (loopCnt > 10) {
 addr = 110101;
 break;
 }
 var prov = util.str_pad(util.rand(50), 2, '0');
 var city = util.str_pad(util.rand(20), 2, '0');
 var area = util.str_pad(util.rand(20), 2, '0');
 var addrTest = [ prov, city, area ].join('');
 if (GB2260[addrTest]) {
 addr = addrTest;
 break;
 }
 }
 } else {
 addr = 110101;
 }
 
 // 出生年
 var yr = util.str_pad(util.rand(99, 50), 2, '0');
 var mo = util.str_pad(util.rand(12, 1), 2, '0');
 var da = util.str_pad(util.rand(28, 1), 2, '0');
 if (isFifteen) {
 return addr + yr + mo + da
 + util.str_pad(util.rand(999, 1), 3, '1');
 }
 
 yr = '19' + yr;
 var body = addr + yr + mo + da
 + util.str_pad(util.rand(999, 1), 3, '1');
 
 // 位置加权
 var posWeight = [];
 for (var i = 18; i > 1; i--) {
 var wei = util.weight(i);
 posWeight[i] = wei;
 }
 
 // 累加body部分与位置加权的积
 var bodySum = 0;
 var bodyArr = body.split('');
 for (var j = 0; j < bodyArr.length; j++) {
 bodySum += (parseInt(bodyArr[j], 10) * posWeight[18 - j]);
 }
 
 // 得出校验码
 var checkBit = 12 - (bodySum % 11);
 if (checkBit == 10) {
 checkBit = 'X';
 } else if (checkBit > 10) {
 checkBit = checkBit % 11;
 }
 checkBit = (typeof checkBit === 'number' ? checkBit.toString()
 : checkBit);
 
 return (body + checkBit);
 }
 
 };// _IDValidator
 GB2260 = GB2260 == null ? "" : GB2260;
 return new _IDValidator(GB2260);
}

调用如下:

//新建普通实例
var Validator = new IDValidator();
 
//验证号码是否合法,合法返回true,不合法返回false
Validator.isValid(code);
 
//号码合法时返回分析信息(地区、出生日期、性别、校验位),不合法返回false
Validator.getInfo(code);
 
//仿造一个18位身份证号
Validator.makeID();
 
//仿造一个15位身份证号
Validator.makeID(true);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
对javascript的一点点认识总结《javascript高级程序设计》读书笔记
Nov 30 Javascript
非主流的textarea自增长实现js代码
Dec 20 Javascript
Extjs 4.x 得到form CheckBox 复选框的值
May 04 Javascript
jQuery 浮动导航菜单适合购物商品类型的网站
Sep 09 Javascript
jQuery Masonry瀑布流插件使用详解
Nov 17 Javascript
jQuery添加options点击事件并传值实例代码
May 18 Javascript
微信小程序 参数传递详解
Oct 24 Javascript
bootstrap fileinput实现文件上传功能
Aug 23 Javascript
JS跨域请求的问题解析
Dec 03 Javascript
使用Vue.js中的过滤器实现幂方求值的方法
Aug 27 Javascript
layui 实现加载动画以及非真实加载进度的方法
Sep 23 Javascript
Vue extend的基本用法(实例详解)
Dec 09 Javascript
Vue原理剖析 实现双向绑定MVVM
May 03 #Javascript
利用node.js写一个爬取知乎妹纸图的小爬虫
May 03 #Javascript
Vue实现双向数据绑定
May 03 #Javascript
Angular 4.x 路由快速入门学习
May 03 #Javascript
javaScript 逻辑运算符使用技巧整理
May 03 #Javascript
浅谈Node.js轻量级Web框架Express4.x使用指南
May 03 #Javascript
vue的Virtual Dom实现snabbdom解密
May 03 #Javascript
You might like
PHP利用str_replace防注入的方法
2013/11/10 PHP
在PHP站点的页面上添加Facebook评论插件的实例教程
2016/01/08 PHP
win10环境PHP 7 安装配置【教程】
2016/05/09 PHP
php set_include_path函数设置 include_path 配置选项
2016/10/30 PHP
thinkPHP框架实现生成条形码的方法示例
2018/06/06 PHP
Firefox和IE浏览器兼容JS脚本写法小结
2008/07/07 Javascript
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
2012/06/22 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
通过Jquery的Ajax方法读取将table转换为Json
2014/05/31 Javascript
使用JavaScript 实现的人脸检测
2015/03/24 Javascript
jQuery插件Slider Revolution实现响应动画滑动图片切换效果
2015/06/05 Javascript
Node.js编程中客户端Session的使用详解
2015/06/23 Javascript
基于insertBefore制作简单的循环插空效果
2015/09/21 Javascript
JavaScript setTimeout使用闭包功能实现定时打印数值
2015/12/18 Javascript
郁闷!ionic中获取ng-model绑定的值为undefined如何解决
2016/08/27 Javascript
angularjs之$timeout指令详解
2017/06/13 Javascript
Vue实现侧边菜单栏手风琴效果实例代码
2018/05/31 Javascript
微信小程序返回上一页传参并刷新过程解析
2019/12/13 Javascript
[01:00:59]VP VS VG Supermajor小组赛胜者组第二轮 BO3第二场 6.2
2018/06/03 DOTA
盘点提高 Python 代码效率的方法
2014/07/03 Python
Python中使用装饰器来优化尾递归的示例
2016/06/18 Python
使用Python中的tkinter模块作图的方法
2017/02/07 Python
详解python3中socket套接字的编码问题解决
2017/07/01 Python
Python any()函数的使用方法
2019/10/28 Python
Python运行异常管理解决方案
2020/03/09 Python
python搜索算法原理及实例讲解
2020/11/18 Python
一款简洁的纯css3代码实现的动画导航
2014/10/31 HTML / CSS
Chain Reaction Cycles芬兰:世界上最大的在线自行车商店
2017/12/06 全球购物
韩国保养品、日本药妆购物网:小三美日
2018/12/30 全球购物
HolidayLettings英国:预订最好的度假公寓、别墅和自助式住宿
2019/08/27 全球购物
生物技术毕业生自荐信
2013/10/23 职场文书
应届毕业生应聘自荐信范文
2014/02/26 职场文书
优秀德育工作者事迹材料
2014/05/07 职场文书
建筑工程催款函
2015/06/24 职场文书
七一活动主持词
2015/06/29 职场文书
详解Vue的options
2021/05/15 Vue.js