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 相关文章推荐
extjs tabpanel限制选项卡数量实现思路及代码
Apr 02 Javascript
与Math.pow 相反的函数使用介绍
Aug 04 Javascript
jQuery实现转动随机数抽奖效果的方法
May 21 Javascript
jquery 中ajax执行的优先级
Jun 22 Javascript
浅析如何利用JavaScript进行语音识别
Oct 27 Javascript
bootstrap实现每隔5秒自动轮播效果
Dec 20 Javascript
AngularJS constant和value区别详解
Feb 28 Javascript
node打造微信个人号机器人的方法示例
Apr 26 Javascript
JavaScript实现的开关灯泡点击切换特效示例
Jul 08 Javascript
教你如何用Node实现API的转发(某音乐)
Sep 20 Javascript
vue 实现路由跳转时更改页面title
Nov 05 Javascript
vue使用refs获取嵌套组件中的值过程
Mar 31 Vue.js
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
codeigniter显示所有脚本执行时间的方法
2015/03/21 PHP
PHP session垃圾回收机制实例分析
2019/06/28 PHP
jQuery中文入门指南,翻译加实例,jQuery的起点教程
2007/02/09 Javascript
javascript实现的动态文字变换
2007/07/28 Javascript
jquery.messager.js插件导致页面抖动的解决方法
2013/07/14 Javascript
推荐8款jQuery轻量级树形Tree插件
2014/11/12 Javascript
个人网站留言页面(前端jQuery编写、后台php读写MySQL)
2016/05/03 Javascript
js控制div层的叠加简单方法
2016/10/15 Javascript
浅谈JavaScript的计时器对象
2016/12/26 Javascript
JS使用cookie实现只出现一次的广告代码效果
2017/04/22 Javascript
从setTimeout看js函数执行过程
2017/12/19 Javascript
解决vue的变量在settimeout内部效果失效的问题
2018/08/30 Javascript
通过cordova将vue项目打包为webapp的方法
2019/02/02 Javascript
浅谈vue加载优化策略
2019/03/19 Javascript
Node.js中Koa2在控制台输出请求日志的方法示例
2019/05/02 Javascript
微信小程序开发摇一摇功能
2019/11/22 Javascript
JavaScript canvas实现雪花随机动态飘落
2020/02/08 Javascript
JavaScript 声明私有变量的两种方式
2021/02/05 Javascript
Python获取网页上图片下载地址的方法
2015/03/11 Python
Python生成器(Generator)详解
2015/04/13 Python
对python中的装包与解包实例详解
2019/08/24 Python
Python读取表格类型文件代码实例
2020/02/17 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
序列化Python对象的方法
2020/08/01 Python
H5 canvas实现贪吃蛇小游戏
2017/07/28 HTML / CSS
Etam艾格英国官网:法国著名女装品牌
2019/04/15 全球购物
金融专业大学生职业生涯规划范文
2014/01/16 职场文书
大型演出策划方案
2014/05/28 职场文书
经营理念口号
2014/06/21 职场文书
基层党建工作汇报材料
2014/08/15 职场文书
退学证明范本3篇
2014/10/29 职场文书
毕业设计指导教师评语
2014/12/30 职场文书
商务英语邮件开头问候语
2015/11/10 职场文书
《自己的花是让别人看的》教学反思
2016/02/19 职场文书
小学生节约用水倡议书
2019/08/12 职场文书
4种方法python批量修改替换列表中元素
2022/04/07 Python