6.4 KiB
6.4 KiB
文本句子分割工具技术文档
本模块提供两个核心函数,用于智能地将一段包含中英文混合内容的文本按句子进行分割,同时保留对话部分不被错误切分。适用于自然语言处理、文本预处理等场景。
📌 模块功能概览
| 函数名 | 功能描述 |
|---|---|
split_english_sentences(text) |
分割纯英文文本为句子列表,避免在缩写词处误切分 |
split_text_with_dialog_preserved(text) |
分割中英文混合文本,并完整保留引号内的对话内容 |
✅ 1. split_english_sentences(text)
功能说明
该函数用于将英文文本正确分割为独立句子,特别处理了以下常见问题:
- 句子结尾标点后缺少空格(如
"Hello.World"→"Hello. World") - 避免在常见缩写词(如 Dr., U.S.A.)处错误断句
- 支持
.,!,?作为句子结束符
参数
| 参数 | 类型 | 说明 |
|---|---|---|
text |
str |
待分割的英文文本字符串 |
返回值
List[str]: 分割后的句子列表,每个元素为一个独立句子(已去除首尾空白)
实现逻辑详解
步骤 1:修复紧连句点
text = re.sub(r'([a-zA-Z])\\.([A-Z])', r'\\1. \\2', text)
- 目的:修复形如
Hello.World的情况,在句点后添加空格。 - 正则解释:
([a-zA-Z]):匹配前一个字母\\.:匹配句点.([A-Z]):匹配后一个大写字母(新句子开头)
- 示例:
"It is cold.Today it will snow."→"It is cold. Today it will snow."
步骤 2:保护缩写词中的句点
abbreviations = r"(Mr|Mrs|Ms|Dr|St|Jr|Sr|vs|i\\.e|e\\.g|U\\.S\\.A|U\\.K)\\."
text = re.sub(abbreviations, lambda m: m.group(0).replace('.', '<DOT>'), text)
- 目的:防止在
Dr.或U.S.A.等缩写处分割。 - 使用
<DOT>临时替换缩写中的句点,避免被当作句子结束。 - 支持的缩写包括:
Mr.,Mrs.,Ms.,Dr.,St.,Jr.,Sr.,vs.i.e.,e.g.,U.S.A.,U.K.
步骤 3:正则分割句子
sentences = re.split(r'(?<=[.!?])\\s+', text.strip())
- 利用正向后视断言
(?<=...)在.,!,?后面的空白处分割。 - 确保只在句子结束符后的空格处分割,而非所有空格。
步骤 4:还原缩写中的句点
sentences = [s.replace('<DOT>', '.') for s in sentences if s.strip()]
- 将之前替换成
<DOT>的句点恢复为正常句点。 - 过滤掉空字符串或仅空白的内容。
示例调用
text = "Dr. Smith went to the U.S.A. He said, 'Hello world!' How are you?"
result = split_english_sentences(text)
print(result)
# 输出:
# ['Dr. Smith went to the U.S.A.', "He said, 'Hello world!'", 'How are you?']
✅ 2. split_text_with_dialog_preserved(text)
功能说明
此函数用于处理中英文混合文本,并确保双引号或中文引号包裹的对话内容整体保留,不会在内部被切断。
特别适用于小说、剧本、访谈记录等含大量对话的文本。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
text |
str |
包含中英文和可能对话的原始文本 |
返回值
List[str]: 分割后的文本片段列表,每项是一个句子或完整的对话块。
实现逻辑详解
步骤 1:清理换行与回车
text = ''.join(text.split('\r'))
text = ' '.join(text.split('\n'))
- 移除
\r回车符 - 将所有
\n替换为空格,避免跨行断裂影响匹配
步骤 2:定义对话匹配模式
dialog_pattern = r'([“\"](.*?)[”\"])'
- 匹配使用中文左/右引号
“”或英文双引号""包裹的内容 (.*?)非贪婪捕获中间内容flags=re.DOTALL允许匹配跨行对话
步骤 3:逐段提取并处理非对话 + 对话部分
通过 re.finditer() 遍历所有对话块:
a. 提取当前对话前的非对话文本
non_dialog = text[last_idx:start]
b. 尝试用中文规则分割(优先中文句末标点)
sentences = re.findall(r'[^。!?!?]*[。!?!?]', non_dialog, re.MULTILINE)
- 匹配以
。,!,?,!,?结尾的中文/英文句子 - 若无结果,则调用
split_english_sentences()处理纯英文段落
c. 添加已分割的句子到结果
parts.extend([s.strip() for s in sentences if s.strip()])
d. 完整保留整个对话块(不分割)
parts.append(match.group(1).strip()) # 如:“你好!”
e. 更新索引位置
last_idx = end # 下一次从对话结束后开始
步骤 4:处理最后一个对话之后的剩余文本
重复上述非对话处理流程,完成收尾。
示例调用
text = '''
张三说:“你今天过得怎么样?”
李四回答:“还不错!我刚从U.S.A回来。”
然后他笑了笑。
'''
result = split_text_with_dialog_preserved(text)
for i, part in enumerate(result):
print(f"{i+1}. {part}")
输出示例
1. 张三说:“你今天过得怎么样?”
2. “还不错!我刚从U.S.A回来。”
3. 然后他笑了笑。
注意:对话内容作为一个整体保留,其中
U.S.A不会被错误切开。
⚠️ 注意事项与限制
| 项目 | 说明 |
|---|---|
| 缩写支持有限 | 当前硬编码了常用缩写,若需扩展可修改 abbreviations 正则 |
| 仅支持双引号对话 | 单引号(如 'hello')不会被视为对话块 |
| 不支持嵌套引号 | 如 “他说:‘你好’” 可能导致匹配异常 |
| 性能建议 | 对超长文本建议分段处理,避免正则效率下降 |
🧪 测试建议
推荐对以下类型文本进行测试验证:
- 含缩写的英文句子(如
Dr. John works in the U.S.A.) - 中英混合带对话(如
小明说:“I'm fine!”) - 多行对话结构
- 特殊符号与标点组合
📦 总结
本工具包提供了稳健的句子分割能力,尤其适合需要保留语义完整性(特别是对话)的 NLP 前处理任务。结合正则表达式与临时标记机制,有效解决了缩写误切与对话破坏的问题。
✅ 推荐用于:文本清洗、对话系统预处理、文学作品分析等场景。
📌 作者: 开发者
📅 最后更新: 2025年4月5日