拜读了不动声色的蜗牛老师的博客《最严格的身份证校验(JavaScript版)》,觉得非常好用,参考着写下这篇博客,作为记录。代码部分基本都是不动声色的蜗牛老师原来的,根据实际项目情况以及自己的代码习惯修改了些,逻辑修改微乎其微。
简单说明一下居民身份证号码的规则:
由18位组成:前六位为行政区划代码,第七至第十四位为出生日期码,第15至17位为顺序码,第17位代表性别(奇数为男,偶数为女),第18位为校验码。作为尾号的校验码,是由号码编制单位按统一的公式计算出来的,如果某人的尾号是0-9,都不会出现X,但如果尾号是10,那么就得用X来代替。
身份证中第十八位数字的计算方法为:
(一)、将前面的身份证号码17位数分别乘以不同的系数(加权因子)。从第一位到第十七位的系数分别为:7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2。
(二)、将这17位数字和系数相乘的结果相加。
(三)、用加出来和除以11,看余数是多少?
(四)、余数只可能有0 、1、 2、 3、 4、 5、 6、 7、 8、 9、 10这11个数字。其分别对应的最后一位身份证的号码为1、0、X、9、8、7、6、5、4、3、2.。比如说,如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。
倒数第二位是用来表示性别的
例如:某男性的身份证号码是34052419800101001X。我们要看看这个身份证是不是合法的身份证。
首先:我们得出,前17位的加权乘积和是189
然后:用189除以11得出的结果是17 + 2/11,也就是说余数是2。
最后:通过对应规则就可以知道余数2对应的数字是x。所以,这是一个合格的身份证号码。
js代码:
function validateCertificateNo(certificateNo) {
if (!certificateNo) {
console.log("身份证号码不可以为空!");
return false;
}
if (certificateNo.length == 18) {
let address = certificateNo.substring(0, 6); // 6位,地区代码
let birthday = certificateNo.substring(6, 14); // 8位,出生日期
let sequenceCode = certificateNo.substring(14, 17); // 3位,顺序码:奇为男,偶为女
let checkCode = certificateNo.substring(17); // 1位,校验码:检验位
console.log("身份证号码:" + certificateNo + "、地区代码:" + address + "、出生日期:" + birthday + "、顺序码:" + sequenceCode + "、校验码:" + checkCode);
const province = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江 ",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北 ",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏 ",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "新疆",
71: "台湾",
81: "香港",
82: "澳门",
91: "国外"
};
// 判断前两位地区代码是否有效
if (!province[parseInt(address.substr(0, 2))]) {
console.log("前两位地区代码无效,请重新输入!!!");
return false;
}
let year = birthday.substring(0, 4);
let month = birthday.substring(4, 6);
let day = birthday.substring(6);
let tempDate = new Date(year, parseFloat(month) - 1, parseFloat(day));
// 这里用getFullYear()获取年份,避免千年虫问题
if ((tempDate.getFullYear() != parseFloat(year) || tempDate.getMonth() != parseFloat(month) - 1 || tempDate.getDate() != parseFloat(day))) {
console.log("出生日期无效,请重新输入!!!");
return false;
}
const weightedFactors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1]; // 加权因子
const valideCode = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]; // 身份证校验码值,其中10代表X
let certificateNoArray = certificateNo.split(""); // 得到身份证数组
let sum = 0; // 声明加权求和变量
if (certificateNoArray[17].toLowerCase() == 'x') {
certificateNoArray[17] = 10; // 将最后位为x的验证码替换为10
}
for (let i = 0; i < 17; i++) {
sum += weightedFactors[i] * certificateNoArray[i]; // 加权求和
}
valCodePosition = sum % 11; // 得到验证码所在位置
if (certificateNoArray[17] == valideCode[valCodePosition]) {
console.log("身份证号码有效,性别为:" + ((sequenceCode % 2 == 0) ? "女" : "男") + "!");
return true;
} else {
console.log("校验码无效,请重新输入!!!");
return false;
}
}
console.log("身份证号码位数不正确,请重新输入!!!");
return false;
}