4、Python法律文本处理基础:正则表达式在法条提取中的应用、jieba分词与法律词典定制、停用词过滤与文本清洗

做法律大模型,第一步不是调模型,而是搞定文本。

法律文本有多「脏」,做过的人都知道。条款编号不统一、标点符号乱飞、各种「的」「地」「得」混着用。我刚开始做法律NLP项目时,光清洗数据就花了两周。嗯,今天就把这些坑一次性讲清楚。

4.1 正则表达式:法条提取的瑞士军刀

正则表达式,说白了就是一套「文本匹配规则」。你告诉它你要找什么模式,它帮你从海量文本里捞出来。

核心场景:从裁判文书、法律法规中提取条款编号、案号、日期等结构化信息。

4.1.1 法条编号提取

法律文本里最常见的模式是什么?「第X条」「第X章」「第X节」。我见过最离谱的写法是「第 一 条」中间带空格的。正则表达式怎么处理?

import re

text = "根据《中华人民共和国合同法》第一百零七条、第二百零一条的规定..."
# 提取所有"第X条"模式
pattern = r'第[一二三四五六七八九十百千零]+条'
matches = re.findall(pattern, text)
print(matches)  # ['第一百零七条', '第二百零一条']

# 更通用的写法:支持阿拉伯数字和中文数字
pattern2 = r'第[\d一二三四五六七八九十百千零]+条'
matches2 = re.findall(pattern2, text)
print(matches2)  # ['第一百零七条', '第二百零一条']

我的经验:中文数字转阿拉伯数字是个大坑。我曾经写过一个转换函数,把「一百零七」转成107,结果「二百零一」转成了201。后来发现「零」的处理要特别小心——「一百零七」是107,「一百一十」是110。建议直接用字典映射,别自己写逻辑。

4.1.2 案号提取

案号格式五花八门:「(2023)京01民初123号」「(2022)沪0115刑初456号」。括号有全角半角,年份有四位两位。

text = "本院于2023年5月10日立案受理了(2023)京01民初123号案件"
pattern = r'[((]\d{4}[))][\u4e00-\u9fa5]{2,4}\d{1,4}[民刑行]初?\d+号'
match = re.search(pattern, text)
if match:
    print(match.group())  # (2023)京01民初123号

注意:不同法院的案号格式差异很大。基层法院用「民初」,中级法院用「民初」或「民终」,高级法院还有「民再」。我建议你建一个案号格式库,把常见模式都列进去。

4.1.3 日期提取

法律文书里的日期格式:「2023年5月10日」「2023-05-10」「2023/05/10」。还有更坑的:「二〇二三年五月十日」。

text = "判决日期:二〇二三年五月十日"
# 中文日期转数字
chinese_num = {'〇': '0', '一': '1', '二': '2', '三': '3', '四': '4',
               '五': '5', '六': '6', '七': '7', '八': '8', '九': '9'}
for cn, num in chinese_num.items():
    text = text.replace(cn, num)
print(text)  # 判决日期:2023年5月10日

4.2 jieba分词与法律词典定制

分词是中文NLP的基础。但通用分词器对法律文本效果很差——「原告」「被告」「诉讼请求」这些词,jieba默认可能给你切成「原」「告」「诉讼」「请求」。

4.2.1 为什么需要法律词典?

你想想看,法律文本里有大量专有名词:

  • 法律术语:「不可抗力」「违约责任」「诉讼时效」
  • 机构名称:「最高人民法院」「北京市第一中级人民法院」
  • 案由:「民间借贷纠纷」「买卖合同纠纷」

jieba默认词典里没有这些词,分出来就是一堆碎片。

4.2.2 定制法律词典

import jieba

# 加载自定义词典
jieba.load_userdict('legal_dict.txt')

# legal_dict.txt 内容示例:
# 不可抗力 5 n
# 违约责任 5 n
# 诉讼时效 5 n
# 最高人民法院 5 nt
# 民间借贷纠纷 5 nz

text = "因不可抗力导致合同无法履行,不承担违约责任"
words = jieba.lcut(text)
print(words)
# 输出:['因', '不可抗力', '导致', '合同', '无法', '履行', ',', '不', '承担', '违约责任']

我的习惯:词典文件每行三个字段:词、词频、词性。词频建议设5-10,太高会影响其他词的分词效果。词性标注用n(名词)、nt(机构名)、nz(其他专名)。

4.2.3 动态添加与删除

# 动态添加
jieba.add_word("诉讼请求")
jieba.add_word("事实与理由")

# 动态删除(防止错误分词)
jieba.del_word("诉讼")
jieba.del_word("请求")

避坑指南:我曾经在项目中动态添加了1000多个法律词,结果分词速度从每秒10万字降到了2万字。后来发现是词典太大导致的。建议:只添加高频且确实需要合并的词,别一股脑全加进去。

4.3 停用词过滤与文本清洗

法律文本里充斥着大量「的」「了」「在」「是」这类停用词。它们对语义理解没什么帮助,反而会增加噪声。

4.3.1 构建法律停用词表

通用停用词表对法律文本不够用。我建议你专门建一个法律停用词表:

# legal_stopwords.txt 示例
的
了
在
是
为
所
被
由
于
以
及
等
其
该
之
与
或
但
而
且
虽
然
因为
所以
因此
据此
为此
鉴于
关于
对于
按照
依照
根据
def load_stopwords(filepath):
    with open(filepath, 'r', encoding='utf-8') as f:
        stopwords = set([line.strip() for line in f])
    return stopwords

stopwords = load_stopwords('legal_stopwords.txt')

def filter_stopwords(words, stopwords):
    return [w for w in words if w not in stopwords and len(w) > 1]

text = "根据《中华人民共和国合同法》的规定,当事人应当按照约定履行自己的义务"
words = jieba.lcut(text)
filtered = filter_stopwords(words, stopwords)
print(filtered)
# 输出:['中华人民共和国合同法', '规定', '当事人', '按照', '约定', '履行', '自己', '义务']

注意:「自己」在法律文本中有时有特殊含义(如「自己代理」),要不要过滤取决于你的任务。我一般保留长度大于1的词,因为单字词在法律文本中信息量很低。

4.3.2 文本清洗全流程

一个完整的法律文本清洗流程,我总结为五步:

  1. 去除无关字符:HTML标签、特殊符号、多余空格
  2. 统一格式:全角转半角、繁体转简体
  3. 正则提取:提取法条、案号、日期等结构化信息
  4. 分词与词典匹配:加载法律词典,提高分词准确率
  5. 停用词过滤:去除无意义词,保留关键信息
import re
import jieba

def clean_legal_text(text):
    # 1. 去除HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    
    # 2. 全角转半角
    text = text.replace(',', ',').replace('。', '.').replace(';', ';')
    text = text.replace('(', '(').replace(')', ')').replace('《', '<').replace('》', '>')
    
    # 3. 去除多余空格和换行
    text = re.sub(r'\s+', ' ', text)
    
    # 4. 提取法条(示例)
    articles = re.findall(r'第[\d一二三四五六七八九十百千零]+条', text)
    
    # 5. 分词
    words = jieba.lcut(text)
    
    # 6. 停用词过滤
    stopwords = load_stopwords('legal_stopwords.txt')
    filtered = [w for w in words if w not in stopwords and len(w) > 1]
    
    return filtered, articles

text = "<p>根据《合同法》第107条,当事人一方不履行合同义务的,应当承担违约责任。</p>"
words, articles = clean_legal_text(text)
print("分词结果:", words)
print("提取法条:", articles)

4.4 本章知识体系

下面这张图展示了本章的核心逻辑:从原始法律文本到结构化数据的完整流程。

法律文本处理知识体系 原始法律文本 正则表达式:法条/案号/日期提取 jieba分词 + 法律词典定制 停用词过滤 + 文本清洗 结构化数据 第1步 第2步 第3步

说白了,这三步是法律NLP的「基本功」。正则负责「捞」结构化信息,分词负责「切」出语义单元,清洗负责「去」掉噪声。每一步都有坑,但踩过之后,你会发现法律文本其实没那么可怕。

总结:法律文本处理的核心不是技术有多炫,而是对法律文本模式的理解有多深。正则表达式、分词、清洗,这三板斧用好了,80%的法律NLP问题都能解决。

专注资料整理