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 相关文章推荐
jquery isEmptyObject判断是否为空对象的函数
Feb 14 Javascript
实现只能输入数字的input不用replace方法
Sep 12 Javascript
鼠标滚轮改变图片大小的示例代码
Nov 20 Javascript
jquery validate.js表单验证入门实例(附源码)
Nov 10 Javascript
js实现将选中内容分享到新浪或腾讯微博
Dec 16 Javascript
javascript每日必学之封装
Feb 23 Javascript
jQuery实现鼠标经过购物车出现下拉框代码(推荐)
Jul 21 Javascript
jQuery中delegate()方法的用法详解
Oct 13 Javascript
jquery.tableSort.js表格排序插件使用方法详解
Aug 12 Javascript
解决微信二次分享不显示摘要和图片的问题
Aug 18 Javascript
vue组件之Alert的实现代码
Oct 17 Javascript
详解Vue前端对axios的封装和使用
Apr 01 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的curl实现get和post的代码
2008/08/23 PHP
PHP冒泡排序算法代码详细解读
2011/07/17 PHP
如何使用php输出时间格式
2013/08/31 PHP
PHP实现的函数重载功能示例
2018/08/03 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
JS 添加千分位与去掉千分位的示例
2013/07/11 Javascript
深入剖析JavaScript中的枚举功能
2014/03/06 Javascript
Javascript变量的作用域和作用域链详解
2015/04/02 Javascript
javascript每日必学之封装
2016/02/23 Javascript
Javascript中for循环语句的几种写法总结对比
2017/01/23 Javascript
详解用node编写自己的cli工具
2017/05/23 Javascript
VUE + UEditor 单图片跨域上传功能的实现方法
2018/02/08 Javascript
JavaScript中变量提升和函数提升的详解
2020/08/07 Javascript
js实现拖拽与碰撞检测
2020/09/18 Javascript
[03:55]2014DOTA2国际邀请赛 Fnatic经理采访赢DK在情理之中
2014/07/10 DOTA
使用Python的Tornado框架实现一个一对一聊天的程序
2015/04/25 Python
CentOS 6.5中安装Python 3.6.2的方法步骤
2017/12/03 Python
Python实现文件信息进行合并实例代码
2018/01/17 Python
Python实现的tcp端口检测操作示例
2018/07/24 Python
Pycharm设置utf-8自动显示方法
2019/01/17 Python
Python3远程监控程序的实现方法
2019/07/15 Python
python 中Arduino串口传输数据到电脑并保存至excel表格
2019/10/14 Python
python属于哪种语言
2020/08/16 Python
Python爬虫过程解析之多线程获取小米应用商店数据
2020/11/14 Python
python自动化发送邮件实例讲解
2021/01/04 Python
美国单身专业人士在线约会网站:EliteSingles
2019/03/19 全球购物
美体小铺波兰官方网站:The Body Shop波兰
2019/09/03 全球购物
编码实现字符串转整型的函数
2012/06/02 面试题
职工运动会感言
2014/02/07 职场文书
工厂车间标语
2014/06/19 职场文书
乡领导班子四风问题对照检查材料
2014/09/25 职场文书
2014年防汛工作总结
2014/12/08 职场文书
合同审查法律意见书
2015/06/04 职场文书
解除处分决定书
2015/06/25 职场文书
Nginx解决403 forbidden的完整步骤
2021/04/01 Servers
MySQL 8.0 Online DDL快速加列的相关总结
2021/06/02 MySQL