3.2 KiB
3.2 KiB
Field Extractor 分析报告
概述
field_extractor.py (1183行) 最初被识别为可优化文件,尝试使用 src/normalize 模块进行重构,但经过分析和测试后发现 不应该重构。
重构尝试
初始计划
将 field_extractor.py 中的重复 normalize 方法删除,统一使用 src/normalize/normalize_field() 接口。
实施步骤
- ✅ 备份原文件 (
field_extractor_old.py) - ✅ 修改
_normalize_and_validate使用统一 normalizer - ✅ 删除重复的 normalize 方法 (~400行)
- ❌ 运行测试 - 28个失败
- ✅ 添加 wrapper 方法委托给 normalizer
- ❌ 再次测试 - 12个失败
- ✅ 还原原文件
- ✅ 测试通过 - 全部45个测试通过
关键发现
两个模块的不同用途
| 模块 | 用途 | 输入 | 输出 | 示例 |
|---|---|---|---|---|
| src/normalize/ | 变体生成 用于匹配 | 已提取的字段值 | 多个匹配变体列表 | "INV-12345" → ["INV-12345", "12345"] |
| field_extractor | 值提取 从OCR文本 | 包含字段的原始OCR文本 | 提取的单个字段值 | "Fakturanummer: A3861" → "A3861" |
为什么不能统一?
-
src/normalize/ 的设计目的:
- 接收已经提取的字段值
- 生成多个标准化变体用于fuzzy matching
- 例如 BankgiroNormalizer:
normalize("782-1713") → ["7821713", "782-1713"] # 生成变体
-
field_extractor 的 normalize 方法:
- 接收包含字段的原始OCR文本(可能包含标签、其他文本等)
- 提取特定模式的字段值
- 例如
_normalize_bankgiro:_normalize_bankgiro("Bankgiro: 782-1713") → ("782-1713", True, None) # 从文本提取
-
关键区别:
- Normalizer: 变体生成器 (for matching)
- Field Extractor: 模式提取器 (for parsing)
测试失败示例
使用 normalizer 替代 field extractor 方法后的失败:
# InvoiceNumber 测试
Input: "Fakturanummer: A3861"
期望: "A3861"
实际: "Fakturanummer: A3861" # 没有提取,只是清理
# Bankgiro 测试
Input: "Bankgiro: 782-1713"
期望: "782-1713"
实际: "7821713" # 返回了不带破折号的变体,而不是提取格式化值
结论
field_extractor.py 不应该使用 src/normalize 模块重构,因为:
- ✅ 职责不同: 提取 vs 变体生成
- ✅ 输入不同: 包含标签的原始OCR文本 vs 已提取的字段值
- ✅ 输出不同: 单个提取值 vs 多个匹配变体
- ✅ 现有代码运行良好: 所有45个测试通过
- ✅ 提取逻辑有价值: 包含复杂的模式匹配规则(例如区分 Bankgiro/Plusgiro 格式)
建议
- 保留 field_extractor.py 原样: 不进行重构
- 文档化两个模块的差异: 确保团队理解各自用途
- 关注其他优化目标: machine_code_parser.py (919行)
学习点
重构前应该:
- 理解模块的真实用途,而不只是看代码相似度
- 运行完整测试套件验证假设
- 评估是否真的存在重复,还是表面相似但用途不同
状态: ✅ 分析完成,决定不重构 测试: ✅ 45/45 通过 文件: 保持 1183行 原样