4. 文本预处理
在法规文本订阅与影响识别系统中,原始文本往往来自政府公报、监管网站、PDF 附件、邮件推送或第三方数据接口。这些文本在进入分类模型和影响识别引擎之前,必须经过一套稳定的预处理流水线。预处理的质量直接决定了后续订阅匹配的准确率、影响识别的召回率以及元数据检索的可用性。本节围绕清洗、分段、标题识别、元数据抽取与标准化五个核心环节展开,帮助学员建立可落地的工程化处理思路。
一、核心原理:预处理是“信息保真”与“结构重建”的平衡
法规文本具有三个显著特征:第一,格式噪声多,PDF 转换后常出现页眉页脚、断行、乱码、全角半角混排;第二,结构层级强,章、节、条、款、项、目构成严格的逻辑树;第三,元数据价值高,发文机关、文号、发布日期、生效日期、失效日期、效力级别等字段是订阅分类的关键特征。预处理的核心原理可以概括为:在去除噪声的同时,尽可能保留法规的语义边界和结构信号,并将非结构化文本转化为带标签的结构化对象。
如果清洗过度,可能删除“第X条”等关键结构标记;如果清洗不足,页眉页脚会污染标题识别和分段结果。因此,预处理不是简单的“文本替换”,而是一个带有领域规则的解析过程。
二、方法流程:五步流水线
建议将预处理设计为可配置的流水线,每一步输出中间结果,便于调试和回溯。典型流程如下:
- 清洗:去除页眉页脚、页码、水印、多余空白、控制字符;统一全角/半角、繁简、换行符;修复 PDF 断行导致的词语断裂。
- 分段:依据法规结构标记(章、节、条、款、项)和自然段边界,将长文本切分为语义完整的段落单元。
- 标题识别:识别文档标题、章标题、节标题、条标题,并建立层级关系。
- 元数据抽取:从正文和属性区提取发文机关、文号、发布日期、生效日期、效力级别、主题词等字段。
- 标准化:对日期、机关名称、文号、效力级别进行归一化,形成统一编码和可比较字段。
工程建议:每一步都保留原始偏移量(offset),这样当后续分类或影响识别出现问题时,可以快速定位到原文位置,避免“黑箱”处理。
三、关键环节详解
1. 清洗:规则与正则的组合
清洗阶段最常见的噪声包括:页眉页脚重复行、页码、PDF 转换产生的孤立字符、HTML 标签残留、全角空格、连续空行。可以使用正则表达式和行频统计相结合的方式。例如,统计每行在文档中出现的次数,若某行重复出现且长度较短,很可能是页眉页脚。
import re
def clean_text(raw: str) -> str:
# 去除 HTML 标签
text = re.sub(r'<[^>]+>', '', raw)
# 统一换行符
text = text.replace('\r\n', '\n').replace('\r', '\n')
# 全角转半角(保留中文标点)
text = text.replace(' ', ' ')
# 去除连续空行
text = re.sub(r'\n{3,}', '\n\n', text)
# 去除行首行尾空白
lines = [line.strip() for line in text.split('\n')]
return '\n'.join(lines)
2. 分段:以“条”为最小语义单元
法规文本的分段不能简单按句号或换行切分。推荐以“第X条”作为最小语义单元,因为“条”是法规中最稳定的引用单位。对于“款”和“项”,可以在“条”内部继续切分。分段时需要处理跨页断行、条款编号缺失、以及“第X条之一”等特殊形式。
import re
ARTICLE_PATTERN = re.compile(r'^第[一二三四五六七八九十百零〇\d]+条')
def split_articles(text: str):
lines = text.split('\n')
articles = []
current = []
for line in lines:
if ARTICLE_PATTERN.match(line.strip()):
if current:
articles.append('\n'.join(current))
current = [line.strip()]
else:
if current:
current.append(line.strip())
if current:
articles.append('\n'.join(current))
return articles
3. 标题识别:层级与模式并重
标题识别需要同时处理文档标题、章标题、节标题和条标题。文档标题通常位于正文开头,字体较大或独立成行;章标题以“第X章”开头;节标题以“第X节”开头;条标题以“第X条”开头。对于没有显式“章/节”标记的规范性文件,可以通过编号模式(如“一、”“(一)”)推断层级。
4. 元数据抽取:规则优先,模型辅助
元数据抽取建议采用“规则优先、模型辅助”的策略。发文机关、文号、日期等字段具有强模式,适合用正则和词典匹配;主题词、效力级别等字段可以结合分类模型。常见字段及抽取方式如下表所示:
| 字段 | 典型模式 | 抽取方式 | 标准化目标 |
|---|---|---|---|
| 发文机关 | “国务院”“中国人民银行” | 词典匹配 + 位置规则 | 统一机构编码 |
| 文号 | “国发〔2024〕1号” | 正则 | 机关简称+年份+序号 |
| 发布日期 | “2024年3月15日” | 正则 + 日期解析 | ISO 8601 |
| 生效日期 | “自2024年5月1日起施行” | 正则 + 语义规则 | ISO 8601 |
| 效力级别 | “行政法规”“部门规章” | 规则 + 分类模型 | 枚举编码 |
5. 标准化:让字段可比较、可检索
标准化是预处理的最后一公里。日期统一为 YYYY-MM-DD;机关名称统一为规范全称并映射到机构编码;文号统一为“机关简称〔年份〕序号”;效力级别统一为枚举值。标准化后的元数据可以直接用于订阅规则匹配和影响识别特征工程。
提示:标准化不是一次性工作,建议建立“机关名称别名词典”和“效力级别映射表”,并支持人工审核和增量更新。
四、案例场景:一条法规从原始文本到结构化对象
假设我们收到一份 PDF 转换后的文本,内容包含页眉“国务院公报”、页码“- 3 -”、正文标题“国务院关于修改《XX条例》的决定”、文号“国发〔2024〕5号”、发布日期“2024年2月1日”、生效日期“自2024年4月1日起施行”。经过清洗后,页眉页码被去除;分段后得到标题段、文号段、正文条款段;标题识别标记出文档标题和“第一条”“第二条”;元数据抽取得到发文机关“国务院”、文号“国发〔2024〕5号”、发布日期“2024-02-01”、生效日期“2024-04-01”、效力级别“行政法规”。最终输出一个 JSON 对象,供后续订阅分类和影响识别使用。
五、误区与复盘
常见误区一:清洗过度。把“第X条”中的“第”字或括号当作噪声删除,导致分段失败。建议清洗规则先白名单后黑名单,保留法规结构标记。
常见误区二:分段只按换行。PDF 转换后换行位置不可靠,必须结合条款编号和语义边界。建议以“条”为主锚点,辅以段落长度和标点特征。
常见误区三:元数据只抽不标准化。“国务院”和“中华人民共和国国务院”如果不统一,订阅规则会漏匹配。建议建立别名词典和编码映射。
常见误区四:忽略中间结果留存。预处理一旦出错,无法回溯到原文位置。建议每一步输出带偏移量的中间文件,并记录处理日志。
复盘时,可以用一组已知法规作为回归测试集,检查清洗后是否丢失条款、分段数量是否与人工标注一致、标题层级是否正确、元数据字段是否完整。只有预处理稳定,后续的订阅分类和影响识别才有可靠的基础。