news 2026/5/3 14:52:10

正则表达式实战:从身份证号校验码反推,教你写出更精准的验证规则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
正则表达式实战:从身份证号校验码反推,教你写出更精准的验证规则

正则表达式实战:从身份证号校验码反推,教你写出更精准的验证规则

身份证号码验证是开发中常见的需求,但大多数开发者只是简单地复制网上的正则表达式,却不知道背后的设计逻辑。本文将带你从校验码的计算公式出发,逆向推导出完整的身份证号验证规则,让你真正掌握正则表达式的设计精髓。

1. 身份证号码的结构解析

18位身份证号码并非随机组合的数字,而是经过精心设计的特征组合码。理解其结构是编写验证规则的基础:

  • 地址码(前6位):代表户籍所在地的行政区划代码
    • 前两位表示省份(如11代表北京,31代表上海)
    • 中间两位表示地级市
    • 后两位表示区县
  • 出生日期码(8位):格式为YYYYMMDD
    • 年份:1900-2099
    • 月份:01-12
    • 日:根据月份和闰年情况变化
  • 顺序码(3位):同一地区同一天出生人员的顺序编号
    • 奇数分配给男性,偶数分配给女性
  • 校验码(1位):根据前17位计算得出,可能是0-9或X

2. 校验码的计算原理

校验码是整个身份证验证系统的核心,理解它的计算方式才能设计出精准的正则表达式。

2.1 加权因子与计算公式

校验码的计算使用了一套固定的加权因子:

位置i: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

计算步骤:

  1. 计算加权和:S = Sum(Ai × Wi)
  2. 计算模:Y = mod(S, 11)
  3. 根据Y值查找校验码:
Y值012345678910
校验码10X98765432

2.2 计算示例

以身份证号"11010519491231002X"为例:

位置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 数字:1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 计算: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 = 157 Y = 157 % 11 = 3 校验码 = X (与第18位一致)

3. 从校验码反推前17位的约束条件

理解了校验码的计算方式后,我们可以逆向推导出前17位必须满足的条件,这些条件将直接转化为正则表达式的各个部分。

3.1 地址码的约束

地址码必须符合国家行政区划编码规则:

  • 第一位:1-9(不能为0)
  • 前两位:有效的省份代码(11-91之间的特定值)
  • 后四位:有效的市县代码

对应的正则部分:

^[1-9]\d{5}

3.2 出生日期码的约束

出生日期是最复杂的部分,需要考虑:

  1. 年份范围:1900-2099

    (19|20)\d{2}
  2. 月份和日期的组合:

    • 31天的月份:01,03,05,07,08,10,12
      (01|03|05|07|08|10|12)(0[1-9]|[12]\d|3[01])
    • 30天的月份:04,06,09,11
      (04|06|09|11)(0[1-9]|[12]\d|30)
    • 2月份:区分闰年和平年
      • 闰年:
        02(0[1-9]|[12]\d)
      • 平年:
        02(0[1-9]|1\d|2[0-8])

3.3 顺序码和校验码

顺序码是3位数字,校验码是数字或X:

\d{3}[\dXx]$

4. 构建完整的正则表达式

结合上述所有约束条件,我们可以构建完整的正则表达式。考虑到闰年判断的复杂性,通常需要根据年份动态生成正则表达式。

4.1 静态正则表达式(区分闰年)

闰年版本:

^[1-9]\d{5}(19|20)\d{2}((01|03|05|07|08|10|12)(0[1-9]|[12]\d|3[01])|(04|06|09|11)(0[1-9]|[12]\d|30)|02(0[1-9]|[12]\d))\d{3}[\dXx]$

平年版本:

^[1-9]\d{5}(19|20)\d{2}((01|03|05|07|08|10|12)(0[1-9]|[12]\d|3[01])|(04|06|09|11)(0[1-9]|[12]\d|30)|02(0[1-9]|1\d|2[0-8]))\d{3}[\dXx]$

4.2 MySQL中的实现方案

在MySQL中,我们可以创建一个函数来动态判断闰年并选择相应的正则表达式:

DELIMITER // CREATE FUNCTION validate_id_card(id_card VARCHAR(18)) RETURNS BOOLEAN DETERMINISTIC BEGIN DECLARE year INT; DECLARE is_leap_year BOOLEAN; DECLARE regex_pattern VARCHAR(300); -- 检查长度 IF LENGTH(id_card) != 18 THEN RETURN FALSE; END IF; -- 提取年份 SET year = SUBSTRING(id_card, 7, 4); -- 判断闰年 SET is_leap_year = (year % 400 = 0) OR (year % 100 != 0 AND year % 4 = 0); -- 设置正则表达式 IF is_leap_year THEN SET regex_pattern = '^[1-9]\\d{5}(19|20)\\d{2}((01|03|05|07|08|10|12)(0[1-9]|[12]\\d|3[01])|(04|06|09|11)(0[1-9]|[12]\\d|30)|02(0[1-9]|[12]\\d))\\d{3}[\\dXx]$'; ELSE SET regex_pattern = '^[1-9]\\d{5}(19|20)\\d{2}((01|03|05|07|08|10|12)(0[1-9]|[12]\\d|3[01])|(04|06|09|11)(0[1-9]|[12]\\d|30)|02(0[1-9]|1\\d|2[0-8]))\\d{3}[\\dXx]$'; END IF; -- 执行验证 RETURN id_card REGEXP regex_pattern; END // DELIMITER ;

5. 验证逻辑的完整实现

除了正则表达式验证外,完整的身份证验证还应包括:

  1. 校验码验证

    def validate_check_digit(id_card): if len(id_card) != 18: return False # 加权因子 weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] # 校验码对应关系 check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] # 计算加权和 total = 0 for i in range(17): total += int(id_card[i]) * weights[i] # 计算校验码 mod = total % 11 expected_check = check_codes[mod] # 比较校验码 return id_card[-1].upper() == expected_check
  2. 地址码验证

    def validate_area_code(id_card): province_codes = ['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'] return id_card[:2] in province_codes
  3. 完整验证流程

    def validate_id_card(id_card): # 基础检查 if not isinstance(id_card, str) or len(id_card) != 18: return False # 正则表达式验证 if not re.match(r'^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$', id_card): return False # 校验码验证 if not validate_check_digit(id_card): return False # 地址码验证 if not validate_area_code(id_card): return False return True

在实际项目中,我发现最常出现问题的环节是校验码计算和闰年判断。特别是在处理大量数据时,预先验证地址码可以快速过滤掉大部分无效数据,提高验证效率。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 14:46:29

如何快速获取八大网盘直链:新手完整指南与效率提升方案

如何快速获取八大网盘直链:新手完整指南与效率提升方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

作者头像 李华
网站建设 2026/5/3 14:45:03

在多模型项目中借助 Taotoken 实现灵活的路由与容灾

在多模型项目中借助 Taotoken 实现灵活的路由与容灾 1. 多模型项目的稳定性挑战 中大型生成式 AI 应用通常需要同时接入多个大模型服务,以满足不同场景下的需求。在实际运行过程中,单一模型服务可能因流量激增、供应商维护或网络波动等原因出现暂时性不…

作者头像 李华
网站建设 2026/5/3 14:39:46

3步掌握鸣潮自动化:从新手到高手的实战指南

3步掌握鸣潮自动化:从新手到高手的实战指南 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 你是否厌倦了《鸣潮》中日复…

作者头像 李华
网站建设 2026/5/3 14:39:30

通达信缠论分析插件:3分钟实现专业级市场结构可视化

通达信缠论分析插件:3分钟实现专业级市场结构可视化 【免费下载链接】Indicator 通达信缠论可视化分析插件 项目地址: https://gitcode.com/gh_mirrors/ind/Indicator 还在为复杂的缠论分析而头疼吗?想要快速识别市场中枢和买卖信号却无从下手&am…

作者头像 李华
网站建设 2026/5/3 14:38:27

如果用C++可以实现手机同时跑3个深度神经网络模型

换成 C 跑神经网络,速度至少快 2~5 倍!而且你现在的卡顿,80% 来自 Java 多模型并发。我给你把原理讲得清清楚楚、一针见血。一、为什么你现在 Java 跑 3 个模型这么卡?1)Java 有 GC(垃圾回收&a…

作者头像 李华