Bladeren bron

feat: 采用difflib的统一差异比较功能,支持生成JSON和Markdown报告

zhch158_admin 1 maand geleden
bovenliggende
commit
18fbf8f769
1 gewijzigde bestanden met toevoegingen van 202 en 0 verwijderingen
  1. 202 0
      compare_use_unified_diff.py

+ 202 - 0
compare_use_unified_diff.py

@@ -0,0 +1,202 @@
+import difflib
+import json
+from typing import List, Dict
+from compare_ocr_results import OCRResultComparator
+
+class OCRResultComparatorUnifiedDiff(OCRResultComparator):
+    # 继承自OCRResultComparator以复用部分功能
+    def __init__(self):
+        super().__init__()
+
+    def generate_unified_diff(self, paras1: List[str], paras2: List[str], file1_path: str, file2_path: str) -> Dict:
+        """
+        生成类似git diff的统一差异格式,并返回结构化数据
+        """
+        # 直接调用进行预处理
+        file1_lines = paras1
+        file2_lines = paras2
+
+        # 使用unified_diff生成差异
+        diff = difflib.unified_diff(
+            file1_lines, 
+            file2_lines, 
+            fromfile=file1_path, 
+            tofile=file2_path,
+            lineterm=''  # 确保每行末尾不添加额外字符
+        )
+        
+        # 将差异生成器转换为列表
+        diff_output = list(diff)
+        
+        # 解析diff输出并生成结构化数据
+        structured_diff = self._parse_unified_diff(diff_output, file1_lines, file2_lines, file1_path, file2_path)
+        
+        return structured_diff
+
+    def _parse_unified_diff(self, diff_lines: List[str], file1_lines: List[str], file2_lines: List[str], 
+                       file1_path: str, file2_path: str) -> Dict:
+        """解析unified diff输出并生成结构化数据"""
+        differences = []
+        current_hunk = None
+        file1_line_num = 0
+        file2_line_num = 0
+        
+        for line in diff_lines:
+            if line.startswith('---') or line.startswith('+++'):
+                continue
+            elif line.startswith('@@'):
+                # 解析hunk头部,例如: @@ -1,5 +1,4 @@
+                import re
+                match = re.match(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@', line)
+                if match:
+                    file1_start = int(match.group(1))
+                    file1_count = int(match.group(2)) if match.group(2) else 1
+                    file2_start = int(match.group(3))
+                    file2_count = int(match.group(4)) if match.group(4) else 1
+                    
+                    current_hunk = {
+                        'file1_start': file1_start,
+                        'file1_count': file1_count,
+                        'file2_start': file2_start,
+                        'file2_count': file2_count
+                    }
+                    file1_line_num = file1_start - 1  # 转为0基索引
+                    file2_line_num = file2_start - 1
+            elif line.startswith(' '):
+                # 未改变的行
+                file1_line_num += 1
+                file2_line_num += 1
+            elif line.startswith('-'):
+                # 文件1中删除的行
+                content = line[1:]  # 去掉'-'前缀
+                differences.append({
+                    'type': 'paragraph',
+                    'position': f'段落{file1_line_num + 1}',
+                    'file1_value': content,
+                    'file2_value': "",
+                    'description': '文件1中独有的段落',
+                    'similarity': 0.0,
+                    'severity': 'medium',
+                    'line_number': file1_line_num + 1,
+                    'change_type': 'deletion'
+                })
+                file1_line_num += 1
+            elif line.startswith('+'):
+                # 文件2中添加的行
+                content = line[1:]  # 去掉'+'前缀
+                differences.append({
+                    'type': 'paragraph',
+                    'position': f'段落{file2_line_num + 1}',
+                    'file1_value': "",
+                    'file2_value': content,
+                    'description': '文件2中独有的段落',
+                    'similarity': 0.0,
+                    'severity': 'medium',
+                    'line_number': file2_line_num + 1,
+                    'change_type': 'addition'
+                })
+                file2_line_num += 1
+    
+        # 计算统计信息
+        stats = {
+            'total_differences': len(differences),
+            'table_differences': 0,  # diff不包含表格差异
+            'paragraph_differences': len(differences),
+            'amount_differences': 0,
+            'high_severity': len([d for d in differences if d.get('severity') == 'high']),
+            'medium_severity': len([d for d in differences if d.get('severity') == 'medium']),
+            'low_severity': len([d for d in differences if d.get('severity') == 'low']),
+            'deletions': len([d for d in differences if d.get('change_type') == 'deletion']),
+            'additions': len([d for d in differences if d.get('change_type') == 'addition'])
+        }
+        
+        return {
+            'differences': differences,
+            'statistics': stats,
+            'file1_tables': 0,
+            'file2_tables': 0,
+            'file1_paragraphs': len(file1_lines),
+            'file2_paragraphs': len(file2_lines),
+            'file1_path': file1_path,
+            'file2_path': file2_path,
+            'diff_type': 'unified_diff'
+        }
+
+    def generate_unified_diff_report(self, paras1: List[str], paras2: List[str], file1_path: str, file2_path: str, output_file: str):
+        """生成unified diff的JSON和Markdown报告"""
+        # 生成结构化diff数据
+        diff_data = self.generate_unified_diff(paras1, paras2, file1_path, file2_path)
+        
+        # 添加时间戳
+        import datetime
+        diff_data['timestamp'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+        
+        # 生成JSON报告
+        json_file = f"{output_file}_unified_diff.json"
+        with open(json_file, 'w', encoding='utf-8') as f:
+            json.dump(diff_data, f, ensure_ascii=False, indent=2)
+        
+        # 生成Markdown报告
+        md_file = f"{output_file}_unified_diff.md"
+        self._generate_unified_diff_markdown(diff_data, md_file)
+        
+        print(f"📄 Unified Diff JSON报告: {json_file}")
+        print(f"📝 Unified Diff Markdown报告: {md_file}")
+        
+        return diff_data
+
+    def _generate_unified_diff_markdown(self, diff_data: Dict, output_file: str):
+        """生成unified diff的Markdown报告"""
+        with open(output_file, 'w', encoding='utf-8') as f:
+            f.write("# OCR结果Unified Diff对比报告\n\n")
+            
+            # 基本信息
+            f.write("## 基本信息\n\n")
+            f.write(f"- **文件1**: `{diff_data['file1_path']}`\n")
+            f.write(f"- **文件2**: `{diff_data['file2_path']}`\n")
+            f.write(f"- **比较时间**: {diff_data.get('timestamp', 'N/A')}\n")
+            f.write(f"- **对比方式**: Unified Diff\n\n")
+            
+            # 统计信息
+            stats = diff_data['statistics']
+            f.write("## 统计信息\n\n")
+            f.write(f"- 总差异数量: **{stats['total_differences']}**\n")
+            f.write(f"- 删除行数: **{stats['deletions']}**\n")
+            f.write(f"- 添加行数: **{stats['additions']}**\n")
+            f.write(f"- 文件1段落数: {diff_data['file1_paragraphs']}\n")
+            f.write(f"- 文件2段落数: {diff_data['file2_paragraphs']}\n\n")
+            
+            # 差异详情
+            if diff_data['differences']:
+                f.write("## 差异详情\n\n")
+                
+                # 按变更类型分组
+                deletions = [d for d in diff_data['differences'] if d['change_type'] == 'deletion']
+                additions = [d for d in diff_data['differences'] if d['change_type'] == 'addition']
+                
+                if deletions:
+                    f.write(f"### 🗑️ 删除内容 ({len(deletions)}项)\n\n")
+                    for i, diff in enumerate(deletions, 1):
+                        f.write(f"**{i}. 第{diff['line_number']}行**\n")
+                        f.write(f"```\n{diff['file1_value']}\n```\n\n")
+                
+                if additions:
+                    f.write(f"### ➕ 新增内容 ({len(additions)}项)\n\n")
+                    for i, diff in enumerate(additions, 1):
+                        f.write(f"**{i}. 第{diff['line_number']}行**\n")
+                        f.write(f"```\n{diff['file2_value']}\n```\n\n")
+                
+                # 详细差异表格
+                f.write("## 详细差异列表\n\n")
+                f.write("| 序号 | 类型 | 行号 | 变更类型 | 内容 | 描述 |\n")
+                f.write("| --- | --- | --- | --- | --- | --- |\n")
+                
+                for i, diff in enumerate(diff_data['differences'], 1):
+                    change_icon = "🗑️" if diff['change_type'] == 'deletion' else "➕"
+                    content = diff['file1_value'] if diff['change_type'] == 'deletion' else diff['file2_value']
+                    f.write(f"| {i} | {change_icon} | {diff['line_number']} | {diff['change_type']} | ")
+                    f.write(f"`{content[:50]}{'...' if len(content) > 50 else ''}` | ")
+                    f.write(f"{diff['description']} |\n")
+            else:
+                f.write("## 结论\n\n")
+                f.write("🎉 **完美匹配!没有发现任何差异。**\n\n")