身份证号校验正则与校验位
现行的 18 位号码分为四段:6 位地址码、8 位出生日期、3 位顺序码、1 位校验位(0 到 9 或字母 X)。正则可以校验长度与各段的形状,日期是否真实存在以及末位校验位是否正确都要用代码算。只判断位数与格式的校验,对随机编造的号码几乎不起作用。
基本信息
| 18 位结构 | 6 位地址码 + 8 位出生日期 + 3 位顺序码 + 1 位校验位 |
|---|---|
| 15 位老格式 | 6 位地址码 + 6 位出生日期 + 3 位顺序码,没有校验位 |
| 校验算法 | ISO 7064 的模 11 减 2 方案:各位乘以加权因子求和,对 11 取余后按映射表得到校验位 |
| 顺序码 | 第 17 位为奇数表示男性、偶数表示女性,这是编码约定而非校验规则,历史数据存在不一致 |
典型使用场景
- 实名信息录入:提交前先做形状与校验位检查,减少明显编造的输入
- 数据清洗:从历史表里筛出格式异常的记录,供人工核对
- 批量导入前预检:把可疑数据集中列出,避免整批失败
- 文本抽取:从合同、报表等文本中定位候选号码,再逐个校验
- 数据脱敏处理:识别字段位置后做掩码,注意不要在校验日志里记录完整号码
形状校验与校验位计算
形状校验与校验位计算
# 形状校验:地址码六位、出生年份四位、月份两位、日期两位、顺序码三位、末位数字或 X
^\d{6}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]$
# 校验位计算:加权因子按位次固定,取余后查映射表
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check = '10X98765432' # 余数 0 到 10 依次对应的校验位
s = sum(int(c) * w for c, w in zip(num[:17], weights)) % 11
if num[17].upper() != check[s]: reject() # 末位统一转大写再比较各段校验方式
| 组成 | 位数 | 校验手段 |
|---|---|---|
| 地址码 | 6 | 正则限形状,是否有效需查行政区划码表 |
| 出生日期 | 8 | 正则限月份与日期范围,大小月与闰年需代码判断 |
| 顺序码 | 3 | 正则限数字,奇偶约定仅作参考 |
| 校验位 | 1 | 按加权取余算法计算后比较,接受大写与小写 X |
正则里的日期分支只能限制到月份 1 到 12、日期 1 到 31,形如 2 月 30 日或 4 月 31 日仍会通过;要严格判定必须用日期库构造一次日期对象,这也是正则与代码分工的典型例子。
身份证号属于敏感个人信息:采集要符合最小必要原则,存储需加密或使用专用字段类型,日志与报错信息中不得出现完整号码,排障时以掩码形式记录。