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