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 相关文章推荐
DOMAssitant最新版 DOMAssistant 2.5发布
Dec 25 Javascript
javascript 程序库的比较(一)之DOM功能
Apr 07 Javascript
js的写法基础分析
Jan 17 Javascript
网页整体变灰白色(兼容各浏览器)实例
Apr 21 Javascript
JavaScript定义类的几种方式总结
Jan 06 Javascript
JavaScript获取伪元素(Pseudo-Element)属性的方法技巧
Mar 13 Javascript
jQuery常用的一些技巧汇总
Mar 26 Javascript
详解Python中logging日志模块在多进程环境下的使用
Dec 26 Javascript
关于Bootstrap按钮组件消除黄框的方法
May 19 Javascript
详解PHP后期静态绑定分析与应用
Mar 21 Javascript
JS字符串与二进制的相互转化实例代码详解
Jun 28 Javascript
layui弹出框Tab选项卡的示例代码
Sep 04 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设计模式 State (状态模式)
2011/06/26 PHP
PHP提示Notice: Undefined variable的解决办法
2012/11/24 PHP
使用Yii2实现主从数据库设置
2016/11/20 PHP
JavaScript Cookie的读取和写入函数
2009/12/08 Javascript
jQuery.prototype.init选择器构造函数源码思路分析
2013/02/05 Javascript
点击按钮自动加关注的代码(sina微博/QQ空间/人人网/腾讯微博)
2014/01/02 Javascript
javascript动态获取登录时间和在线时长
2016/02/25 Javascript
window.open打开窗口被拦截的快速解决方法
2016/08/04 Javascript
关于jQuery中fade(),show()起始位置的一点小发现
2017/04/25 jQuery
解决JS外部文件中文注释出现乱码问题
2017/07/09 Javascript
在Bootstrap开发框架中使用dataTable直接录入表格行数据的方法
2018/10/25 Javascript
记录vue项目中遇到的一点小问题
2019/05/14 Javascript
对Layer弹窗使用及返回数据接收的实例详解
2019/09/26 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
2020/06/11 Javascript
[01:11]辉夜杯战队访谈宣传片—CDEC.Y
2015/12/26 DOTA
学习python (1)
2006/10/31 Python
本地文件上传到七牛云服务器示例(七牛云存储)
2014/01/11 Python
python实现带错误处理功能的远程文件读取方法
2015/04/29 Python
详谈python read readline readlines的区别
2017/09/22 Python
Python利用matplotlib.pyplot绘图时如何设置坐标轴刻度
2018/04/09 Python
pyqt5的QComboBox 使用模板的具体方法
2018/09/06 Python
Python解决线性代数问题之矩阵的初等变换方法
2018/12/12 Python
详解Python3中setuptools、Pip安装教程
2019/06/18 Python
简单了解django缓存方式及配置
2019/07/19 Python
pymysql模块的操作实例
2019/12/17 Python
苹果美国官方商城:Apple美国
2016/08/24 全球购物
Marriott国际:万豪国际酒店查询预订
2017/09/25 全球购物
英国第一摩托车和摩托车越野配件商店:GhostBikes
2019/03/10 全球购物
2014年师德承诺书
2014/05/23 职场文书
企业党员岗位承诺书
2015/04/27 职场文书
学校财务管理制度
2015/08/04 职场文书
公务员学习中国梦心得体会
2016/01/05 职场文书
小学数学教学反思范文
2016/02/16 职场文书
浅谈怎么给Python添加类型标注
2021/06/08 Python
浅谈Python中对象是如何被调用的
2022/04/06 Python
Redis全局ID生成器的实现
2022/06/05 Redis