当前位置: 首页 > news >正文

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

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

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

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

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

http://www.jsqmd.com/news/745068/

相关文章:

  • Qt5.15.2 + VS2019 环境下,手把手教你编译并运行第一个CTK插件化程序
  • 免费离线OCR神器:3分钟解锁图片文字提取新技能
  • B4A滚动视图ScrollView使用方法详解
  • 基于Quivr构建私有RAG知识库:从核心原理到实战部署
  • 2026年怎么搭建Hermes Agent/OpenClaw?阿里云环境配置及token Plan指南
  • ChatGDB:用自然语言对话GDB,AI赋能程序调试新体验
  • Cursor Free VIP:彻底告别试用限制的终极解决方案
  • 如何快速获取八大网盘直链:新手完整指南与效率提升方案
  • 从JEP 428到亿级订单系统:Java 25结构化并发在美团/蚂蚁/京东的真实压测数据与线程模型重构方案,
  • 从Powergui到阻抗曲线:Simulink电力仿真中‘阻抗依频特性测量’功能的保姆级使用指南与结果解读
  • 别再只会换清华源了!Ubuntu 22.04/20.04 apt更新报错‘Could not resolve’的5种排查思路
  • Depth-Anything-V2完整实战指南:如何轻松实现单目深度估计的终极解决方案
  • 告别臃肿模拟器:3分钟在Windows电脑上直接运行安卓应用
  • Windows安卓应用安装终极指南:告别模拟器,原生运行Android应用
  • DIY智能家居遥控器:基于RF-315/433MHz模块的‘学习型’解码与重发实践
  • 别再手动核销了!深入解读SAP自动清账原理:以GR/IR科目为例,看系统如何‘找平’借贷
  • Win11Debloat:一站式Windows系统深度优化与去臃肿终极方案
  • 如何快速掌握Kemono批量下载工具:新手完整指南
  • Sloppy:基于规则优先架构的AI智能体运行时设计与实践
  • Claw Agent集中式管理仪表盘:架构设计与生产部署指南
  • 【国产化中间件适配黄金法则】:Java开发者必须掌握的5大避坑指南与3套可落地代码模板
  • 深入GStreamer插件生态:从‘good’、‘bad’、‘ugly’分类看多媒体开发选型避坑
  • 如何免费扩展工作空间:VirtualMonitor终极虚拟显示器解决方案
  • 5步搞定电脑风扇噪音:Fan Control 终极静音方案指南
  • AI代理工具调用安全治理:实时审批与审计实践指南
  • nRF Connect录播文件导出XML详解:从文件结构到二次开发的可能性
  • 2026年4月做得好的抖音代运营老牌公司推荐分析,短视频获客/企业号代运营/抖音代运营团队,抖音代运营服务商哪家好 - 品牌推荐师
  • Win11Debloat终极指南:如何让Windows 11系统轻盈如飞
  • 5分钟掌握Avidemux:开源视频编辑神器的轻量级剪辑方案
  • Taotoken 用量看板如何帮助团队清晰掌握模型调用成本