UNPKG

libchinaidcard

Version:

中国居民身份证解析库

235 lines (204 loc) 7.92 kB
(function() { const weightFactor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; const checkCode = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; // 直辖市 const municipality = ['11', '12', '31', '50']; function getCheckCode(idCard) { var len = idCard.length; var num = 0; for (let i = 0; i < len; i++) { num = num + Number(idCard.charAt(i)) * weightFactor[i]; } return String(checkCode[num % 11]); } function conv15to18(idCard) { var idCard17 = idCard.slice(0, 6) + "19" + idCard.slice(6); return idCard17 + getCheckCode(idCard17); } function isVaild(idCard) { // 代码没有任何美感, 但是很硬核 // 第一位不存在是 0 的情况 if (idCard.charAt(0) == '0') { return false; } if (idCard.length == 15) { // 验证是否都为数字 if (isNaN(Number(idCard))) { return false; } idCard = conv15to18(idCard); } else if (idCard.length == 18) { // 验证前17位是否都为数字 if (isNaN(Number(idCard.substring(0, 17)))) { return false; } // 验证校验码 if (getCheckCode(idCard.substring(0, 17)) != idCard.charAt(17)) { return false; } } else { return false; } // 验证日期的正确性,利用 Date 的自动纠正日期 var year = Number(idCard.substring(6, 10)); var month = Number(idCard.substring(10, 12)); var day = Number(idCard.substring(12, 14)); var birth = new Date(); birth.setFullYear(year); birth.setMonth(month - 1); birth.setDate(day); // js特性,传参0就是一月了,传参11就是十二月了 if (birth.getFullYear() != year || birth.getMonth() + 1 != month || birth.getDate() != day) { return false; } // 校验地区没写 return true; } function getBirthYear(idCard) { return Number(idCard.substring(6, 10)); } function getBirthMonth(idCard) { return Number(idCard.substring(10, 12)); } function getBirthDay(idCard) { return Number(idCard.substring(12, 14)); } function getBirthDate(idCard) { return { year: Number(idCard.substring(6, 10)), month: Number(idCard.substring(10, 12)), day: Number(idCard.substring(12, 14)) }; } // m 是男, f 是女 function getSex(idCard) { return Number(idCard.charAt(16)) % 2 != 0 ? 'm' : 'f'; } /* 解析前 请把整理成这样 我一般用sublimetext的正则来整理 130000 河北省 130100 石家庄市 130102 长安区 130104 桥西区 130105 新华区 130200 唐山市 130202 路南区 130203 路北区 */ /* 与 直接解析 相比,解析json 快一倍 当然我电脑是这样 解析json (推荐) const areaData = require("./data/xzqh2020.json"); 直接解析 const areaData = parseAreaData("./data/xzqh2020.txt"); */ function parseAreaData(file) { var list = require("fs").readFileSync(file, "UTF-8").split("\n") for (var i in list) { list[i] = list[i].split(" ") list[i][0] = [list[i][0].substring(0, 2), list[i][0].substring(2, 4), list[i][0].substring(4, 6)] list[i][2] = [] } // list 里面长这样 [ [["11","00","00"],"北京市",[...]], ...] var tree = []; var provinceIndex = 0 var cityIndex = 0 for (var i = 0, len = list.length; i < len; i++) { if (typeof tree[provinceIndex - 1] == "undefined" || list[i][0][0] != tree[provinceIndex - 1][0][0]) { // 不同的省 tree.push(list[i]); provinceIndex++; cityIndex = 0; } else { // 同省,可能是市或区 //console.log(list[i][1],municipality.indexOf(list[i][0][0])!=-1) if ( typeof tree[provinceIndex - 1][2][cityIndex - 1] == "undefined" || list[i][0][1] != tree[provinceIndex - 1][2][cityIndex - 1][0][1] || municipality.indexOf(list[i][0][0]) != -1 || (list[i][0][0] == "65" && list[i][0][1] == "90") /* 石河子市以及以下比较特殊,它们不在阿勒泰地区,是并列的 */ ) { // 不同的市 tree[provinceIndex - 1][2].push(list[i]); cityIndex++; } else { // 同市,都是区 tree[provinceIndex - 1][2][cityIndex - 1][2].push(list[i]); } } } return tree; } // # 加载行政区划代码库 // getAreaData: 12.147ms // console.time('getAreaData'); const areaData = require("./data/xzqh2020.json"); // console.timeEnd('getAreaData'); // # 解析行政区划代码库(用于测试) // parseAreaData: 19.494ms // console.time('parseAreaData'); // const areaData0 = parseAreaData("./data/xzqh2020.txt"); // console.timeEnd('parseAreaData'); // # 保存文件 // require("fs").writeFileSync("xzqh2020.json", JSON.stringify(areaData, null, 4), "UTF-8") function getBirthplace(idCard) { var provinceCode = idCard.substring(0, 2); var cityCode = idCard.substring(2, 4); var districtCode = idCard.substring(4, 6); var area = {}; /* 石河子市以及以下比较特殊,它们不在阿勒泰地区,是并列的 */ if (municipality.indexOf(provinceCode) != -1 || (provinceCode == "65" && cityCode == "90")) { for (var i in areaData) { if (areaData[i][0][0] == provinceCode) { area.province = areaData[i][1] for (var j in areaData[i][2]) { if (areaData[i][2][j][0][2] == districtCode) { area.city = areaData[i][2][j][1]; } } } } } else { for (var i in areaData) { if (areaData[i][0][0] == provinceCode) { area.province = areaData[i][1] for (var j in areaData[i][2]) { if (areaData[i][2][j][0][1] == cityCode) { area.city = areaData[i][2][j][1] for (var k in areaData[i][2][j][2]) { if (areaData[i][2][j][2][k][0][2] == districtCode) { area.district = areaData[i][2][j][2][k][1]; } } } } } } } return area; } function getDetails(idCard) { return { year: getBirthYear(idCard), month: getBirthMonth(idCard), day: getBirthDay(idCard), sex: getSex(idCard), birthplace: getBirthplace(idCard) }; } // 没错就是这么暴力 // 不会更方便的写法 module.exports.getCheckCode = getCheckCode; module.exports.conv15to18 = conv15to18; module.exports.isVaild = isVaild; module.exports.getBirthYear = getBirthYear; module.exports.getBirthMonth = getBirthMonth; module.exports.getBirthDay = getBirthDay; module.exports.getBirthDate = getBirthDate; module.exports.getSex = getSex; module.exports.parseAreaData = parseAreaData; module.exports.getBirthplace = getBirthplace; module.exports.getDetails = getDetails; })();