【实战】企业口径一致性检查:用 Python 对齐官网/招聘平台/投标文件三个来源的成立日期与注册地

关键词:企业信息一致性检查、正则抽取、中文日期归一化、NFKC 全角转换、统一社会信用代码校验、多源 diff、Python 实战、数据清洗

摘要

同一家公司的成立日期、注册地、信用代码,在官网、招聘平台、投标文件里经常是三种写法。人眼看不出来,模型更不会帮你判断哪个对。

本文给一套三层实现:正则抽取 → 归一化 → 两两比对,输出 OK / PREFIX_OK / CONFLICT / MISSING 四种状态。代码为示意实现,未做第三方验证。

一、背景

读 Anthropic 的 S-1 拆解报道时注意到一个结构:约 7,800 亿到 8,100 亿美元的算力合同承诺,期限长、价格基本锁死;收入那侧 80% 按量计费。

成本近固定,收入浮动。差额得靠调用量往上填。

对做工程的人来说,这是一个输入条件------当"让答案更少出错"成为产品目标,答案出错的一个常见来源就是多源口径打架。

先把自己的口径对齐,是成本最低的一步。

二、技术方案

2.1 整体结构

复制代码
原始文本 → extract() 正则抽字段 → norm_*() 归一化 → diff() 两两比对 → 状态列表

2.2 归一化:日期

三种常见写法要收敛成一个:

来源 原始写法 归一化后
官网 2020 年 12 月 17 日 2020-12-17
招聘平台 2020-12-17 2020-12-17
投标文件 二〇二〇年十二月十七日 2020-12-17
python 复制代码
import re
import unicodedata

CN_NUM = {"零": 0, "一": 1, "二": 2, "三": 3, "四": 4,
          "五": 5, "六": 6, "七": 7, "八": 8, "九": 9}

def norm_date(s: str) -> str:
    s = unicodedata.normalize("NFKC", s).strip()
    m = re.search(r"(\d{4})\D{1,3}(\d{1,2})\D{1,3}(\d{1,2})", s)
    if m:
        y, mo, d = m.groups()
        return f"{int(y):04d}-{int(mo):02d}-{int(d):02d}"
    m = re.search(r"([零一二三四五六七八九〇]+)年"
                  r"([零一二三四五六七八九十]+)月"
                  r"([零一二三四五六七八九十]+)日", s)
    if m:
        y = "".join(str(CN_NUM.get(c, c)) for c in m.group(1))
        def cn2int(t):
            if "十" in t:
                a, _, b = t.partition("十")
                return (CN_NUM.get(a, 1) if a else 1) * 10 + (CN_NUM.get(b, 0) if b else 0)
            return sum(CN_NUM.get(c, 0) for c in t)
        return f"{int(y):04d}-{cn2int(m.group(2)):02d}-{cn2int(m.group(3)):02d}"
    return s

2.3 归一化:地址与编号

地址不能比相等。省市区前缀在不同来源里写全写简都有,用尾部包含更稳。

python 复制代码
def norm_addr(s: str) -> str:
    s = unicodedata.normalize("NFKC", s).strip()
    for p in ("中国", "浙江省", "浙江省杭州", "杭州市", "杭州"):
        s = s.replace(p, "")
    return s.strip("省市区 \t")

def norm_code(s: str) -> str:
    return unicodedata.normalize("NFKC", s).strip().upper()

2.4 抽取与比对

python 复制代码
from itertools import combinations
from dataclasses import dataclass, field

@dataclass
class Source:
    name: str
    raw: str
    fields: dict = field(default_factory=dict)

PATTERNS = {
    "founded": (r"(?:成立(?:于|时间)?[::]?\s*)?((?:\d{4}\D{1,3}\d{1,2}\D{1,3}\d{1,2})"
                r"|(?:[零一二三四五六七八九〇]+年[零一二三四五六七八九十]+月[零一二三四五六七八九十]+日))", norm_date),
    "address": (r"(?:注册地|地址)[::]?\s*([^\s,,。;;\n]{4,30})", norm_addr),
    "reg_no":  (r"(?:统一社会信用代码|注册号)[::]?\s*([0-9A-Z]{15,20})", norm_code),
}

def extract(src: Source) -> Source:
    for key, (pat, fn) in PATTERNS.items():
        m = re.search(pat, src.raw)
        if m:
            src.fields[key] = fn(m.group(1))
    return src

def diff(sources):
    out = []
    for a, b in combinations(sources, 2):
        for key in set(a.fields) | set(b.fields):
            va, vb = a.fields.get(key), b.fields.get(key)
            if va is None or vb is None:
                st = "MISSING"
            elif va == vb:
                st = "OK"
            elif key == "address" and (va.endswith(vb) or vb.endswith(va)):
                st = "PREFIX_OK"
            else:
                st = "CONFLICT"
            out.append({"field": key, "a": a.name, "b": b.name,
                        "status": st, "detail": f"{va} vs {vb}"})
    return out

三、案例

python 复制代码
srcs = [
    extract(Source("官网", "本公司成立于2020年12月17日,注册地浙江省杭州市余杭区,统一社会信用代码91330100MA2XXXXX1A")),
    extract(Source("招聘平台", "成立时间:2020-12-17  地址:杭州市余杭区  统一社会信用代码:91330100MA2XXXXX1A")),
    extract(Source("投标文件", "公司于二〇二〇年十二月十七日成立,注册地余杭区")),
]
for r in diff(srcs):
    print(r["status"].ljust(10), r["field"].ljust(9), r["a"], "↔", r["b"], "|", r["detail"])

样例输出(本地跑通的格式演示,非统计结论):

复制代码
OK         founded   官网 ↔ 招聘平台 | 2020-12-17 vs 2020-12-17
PREFIX_OK  address   官网 ↔ 招聘平台 | 余杭区 vs 余杭区
OK         founded   官网 ↔ 投标文件 | 2020-12-17 vs 2020-12-17
CONFLICT   reg_no    投标文件 ↔ 招聘平台 | None vs 91330100MA2XXXXX1A

第三行是关键。中文数字写法肉眼容易漏,归一化后能对齐。

四、总结

环节 要点
预处理 NFKC 必须先跑,否则全角数字让正则整段失效
日期 "十"要单独处理:十二=12、二十=20、二十二=22
地址 用尾部包含判断,状态标 PREFIX_OK 而非 OK
输出 只报不修,交人工判断

五、适用边界

  • 正则只覆盖三个字段,扩字段要自己补 PATTERNS。
  • 归一化会漏。漏了原样返回,靠 MISSING 暴露。
  • 不要做自动回写。我试过一版自动以官网值为准,结果官网那页本身是旧稿,反而把错误扩散到另外两个来源。
  • 代码为示意实现,未做第三方验证,勿直接用于生产。
相关推荐
老王IT1 小时前
Go开发环境搭建(window操作系统)
开发语言·后端·golang
学逆向的1 小时前
C++ 匿名命名空间
开发语言·c++·网络安全
AI直播技术杂谈1 小时前
九点整那场,讲品顺序是前一天下午就锁定的
网络·python·ai·秒播
杰克尼1 小时前
今日面试题总结
java·开发语言·人工智能·langchain
青少儿编程课堂2 小时前
蓝桥杯青少组·全国青少年信息素养·电子学会Scratch考级:校园智能抢答器项目解析
c++·python·算法·bfs·信息学竞赛
BD_Marathon2 小时前
【Python】函数_关键字参数
python
昂好的day2 小时前
固高运动控制卡实战(下):点位运动与直线/圆弧插补 API 详解
开发语言·c#
充值内卷2 小时前
[特殊字符] 自己动手做一个类 tldraw 的桌面白板:StepDraw 开源啦(C++ + WebView2 + Canvas)
开发语言·c++
raindayinrain2 小时前
c++对象模型--内存布局,多态,运行时类型识别
开发语言·c++