Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 最全面的身份证号码校验方法 #216

Open
toFrankie opened this issue Feb 26, 2023 · 0 comments
Open

JavaScript 最全面的身份证号码校验方法 #216

toFrankie opened this issue Feb 26, 2023 · 0 comments
Labels
2020 2020 年撰写 JS 与 JavaScript、ECMAScript 相关的文章 代码片段 记录一些代码片段

Comments

@toFrankie
Copy link
Owner

toFrankie commented Feb 26, 2023

关于国家公民身份号码规定如下:

/**
 * 〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定:
 *    公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
 *
 * 地址码编码规则为:
 *    第一位数字表示地区,1 是华北,2 是东北,3 是华东,4 是中南,5 是西南,6 是西北。
 *    第二位数字表示户籍地所在的直辖市、省、自治区,比如在华北地区,1 代表北京市,2 代表天津市等。
 *    第三、四位数字则表示户籍所在地的区、县、县级市、旗。
 *    第五、六位数字是户籍所在地。
 *
 * 出生日期码:
 *    身份证号码第七位到第十四位表示编码对象出生的年、月、日。
 *
 * 顺序码:
 *    身份证号码第十五位到十七位是顺序码,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。
 *
 * 校验码:
 *    身份证号码最后一位为校验码。
 *
 * 校验码的计算方法:
 *    一、将身份证号码前面的 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 位数字就是 X。
 */

身份证校验的 JavaScript 实现如下:

/**
 * 支持 15 位和 18 位身份证号校验
 * 关于身份证号更多规则,请看文件末尾
 *
 * @param {string} code 身份证号码
 * @returns {boolean} 是否检验通过
 */
export const checkIDNumber = code => {
  if (!code || typeof code !== 'string') return false
  // prettier-ignore
  const provinceCodes = ['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']
  const reg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)?$/i
  const codeLen = code.length

  // 格式错误
  if (!reg.test(code) || ![15, 18].includes(codeLen)) {
    return false
  }

  // 地址码错误
  const provinceCode = code.substring(0, 2)
  if (!provinceCodes.includes(provinceCode)) {
    return false
  }

  // 18 位需校验最后一位校验码
  if (codeLen === 18) {
    const codeArr = code.split('')
    const factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    const parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2]
    let sum = 0
    let ai = 0
    let wi = 0
    for (let i = 0; i < 17; i++) {
      ai = codeArr[i]
      wi = factor[i]
      sum += ai * wi
    }
    if (parity[sum % 11] != codeArr[17].toUpperCase()) {
      // 校验码错误
      return false
    }
  }

  return true
}

/**
 * 〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定:
 *    公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
 *
 * 地址码编码规则为:
 *    第一位数字表示地区,1 是华北,2 是东北,3 是华东,4 是中南,5 是西南,6 是西北。
 *    第二位数字表示户籍地所在的直辖市、省、自治区,比如在华北地区,1 代表北京市,2 代表天津市等。
 *    第三、四位数字则表示户籍所在地的区、县、县级市、旗。
 *    第五、六位数字是户籍所在地。
 *
 * 出生日期码:
 *    身份证号码第七位到第十四位表示编码对象出生的年、月、日。
 *
 * 顺序码:
 *    身份证号码第十五位到十七位是顺序码,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。
 *
 * 校验码:
 *    身份证号码最后一位为校验码。
 *
 * 校验码的计算方法:
 *    一、将身份证号码前面的 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 位数字就是 X。
 *
 * 示例:
 *    某女性的身份证号码为【11010519491231002X】, 我们看看这个身份证是不是合法的身份证。
 *    首先我们得出前 17 位的乘积和【(1*7)+(1*9)+(0*10)+(1*5)+(0*8)+(5*4)+(1*2)+(9*1)+(4*6)+(9*3)+(1*7)+(2*9)+(3*10)+(1*5)+(0*8)+(0*4)+(2*2)】是 167,
 *    然后用 167 除以 11 得出的结果是 167/11=15----2,也就是说其余数是 2。
 *    最后通过对应规则就可以知道余数 2 对应的检验码是 X。
 *    所以,可以判定这是一个正确的身份证号码。
 *    请知悉,示例中身份证号码来自国家标准文件附录,请勿非法使用,否则后果自负!
 *
 * 附上:
 *    〖中华人民共和国国家标准 GB 11643-1999〗:http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=080D6FBF2BB468F9007657F26D60013E
 *    关于身份证校验码,可以看:https://baike.baidu.com/item/身份证校验码/3800388
 *
 * 其他:
 *    相比 18 位的身份证号码,15 位的身份证号少了出入年份的前两位,以及最后的校验位。因此将你现在的身份证号码去掉这三位数字,使用本方法也可校验通过
 */

// 地址码前两位,所对应的省市:
// const provinceCodes = {
//   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: '国外'
// }

此方法已收录至:toFrankie/javascript-utils,还有其他一些比较实用的方法,比如中文转拼音等,请看这里

The end.

@toFrankie toFrankie added 代码片段 记录一些代码片段 JS 与 JavaScript、ECMAScript 相关的文章 labels Feb 26, 2023
@toFrankie toFrankie added the 2020 2020 年撰写 label Apr 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2020 2020 年撰写 JS 与 JavaScript、ECMAScript 相关的文章 代码片段 记录一些代码片段
Projects
None yet
Development

No branches or pull requests

1 participant