从Excel/CSV里批量提取身份证号并去重(含4个实跑大坑)

HR、行政、老师常收到一堆混乱表格——同一张身份证写成 320102199003071234、320102 199003071234、320102-19900307-1234 三种样子,人还是同一个人。下面这份脚本本次完整实跑过,不是纸面代码。

核心脚本

import re, csv

# 18位:地区码+8位生日+3位顺序码+校验位;15位旧证也要支持
ID18 = re.compile(r'(?<![0-9Xx])[1-9]\d{5}(?:18|19|20)\d{2}'
                  r'(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[0-9Xx](?![0-9Xx])')
ID15 = re.compile(r'(?<![0-9Xx])[1-9]\d{5}\d{2}'
                  r'(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}(?![0-9Xx])')

def norm(s):                    # 去空格/横线,x统一大写
    return re.sub(r'[\s-]', '', s).upper()

seen = {}
with open('in.csv') as f:
    for r in csv.DictReader(f):
        n = norm(r['证件号'])
        if ID18.fullmatch(n) or ID15.fullmatch(n):
            seen.setdefault(n, r['姓名'])   # 首次出现保留来源姓名

with open('out.csv', 'w', newline='') as f:
    w = csv.writer(f); w.writerow(['姓名', '证件号'])
    for n, name in seen.items():
        w.writerow([name, n])

Excel文件先把 openpyxl.load_workbook(path, data_only=True) 读出每行转成同样结构即可(data_only=True 别忘,否则公式格读到的是公式本身)。

本次实跑踩到的4个真坑

坑1:不归一化,同一个人变三个"人"。去空格/横线之前去重,张三的同一张证会以3种写法各留一条。必须先 norm() 再比对。
坑2:裸写 \d{18} 会从订单号里抠出假身份证。实测一条20位订单号 20261006789012345678,裸正则能从中截出18位"证号"。必须前后加负向断言 (?<![0-9Xx])...(?![0-9Xx]),且校验生日段合法性——本次实跑中订单号被正确挡下。
坑3:结尾是 x 的人会和 X 的人分裂成两条。必须 upper() 统一后再去重,否则同一人重复上报。
坑4:只写18位正则会漏掉15位旧身份证。老员工/老人档案还在用15位旧证,本次实跑 320102900307123 单独支持后才被提出。

实跑结果

7行测试数据(含3种混写格式+1条干扰订单号+15位旧证+X结尾证)→ 正确输出3条唯一身份证号,干扰串0误报,姓名保留首次出现者。

不想自己跑代码?

喵窝资源铺提供人工代做:发来你的表格文件,批量提取去重、拆分合并、清洗格式,19.9元/次起,交付前人工复核。(虚拟服务,交付后不退款;未达承诺免费重做)

更多批量处理干货:免费工具清单(邮件订阅版) · 回到首页