Skip to content

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

@tofrankie

Description

@tofrankie

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

/**
 * 〖中华人民共和国国家标准 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/utils,还有一些比较实用的方法,比如中文转拼音等。

The end.

Metadata

Metadata

Assignees

No one assigned

    Labels

    20202020 年撰写JS与 JavaScript、ECMAScript 相关的文章代码片段记录一些代码片段

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions