#!/usr/bin/env python3 """ OCR乱码检测器 — Step1 OCR完成后必跑。 扫描OCR文本中所有疑似乱码行,输出vision核实清单。 每一处乱码都必须vision对应PDF页面核实后才能进Step2。 用法: python3 ocr-garble-detect.py 判定规则: 1. 多个无意义英文片段(连续3+字母非常见词) 2. 中文占比过低(正常合同行>50%,低于30%标红) 3. 中英混杂碎片(典型OCR乱码模式) 4. 异常符号密集(>20%非正常字符) 误报处理: - 纯数字表格行(日期+金额)→ 正常,核对数字即可 - 邮箱/网址/银行账号 → 正常 - 英文缩写(USD/RMB/PDF)→ 正常 真正需要vision的是:含中文碎片+英文乱码的混合行(如"oe方,同Se") 教训(凤凰文化0701): Line 204 "Se【2024】年【10】月【15】日" 被跳过未核实, 导致整段违约金条款丢失(实际是"初年年租金20%作为违约金")。 代价=审查结论反转("无违约金"→"有20%违约金")。 """ import re, sys def is_garbled(line): """判断一行是否疑似乱码,返回原因或None""" stripped = line.strip() if not stripped or len(stripped) < 5: return None # 1. 连续3+个无意义英文字母组合(非常见英文词) nonsense_en = re.findall(r'[a-zA-Z]{3,}', stripped) common_words = {'pdf','ocr','usd','rmb','the','and','for','with','from', 'www','com','xdf','jpg','png','doc','docx','xlsx','occ', 'vision','step','check','null','true','false'} real_nonsense = [w for w in nonsense_en if w.lower() not in common_words and not re.match(r'^[A-Z]{1,4}$', w)] if len(real_nonsense) >= 2: return f"多个无意义英文片段: {real_nonsense[:3]}" # 2. 单行中文字符占比过低(正常合同行中文应>50%) chinese_chars = len(re.findall(r'[\u4e00-\u9fff]', stripped)) total_chars = len(re.findall(r'\S', stripped)) if total_chars > 10 and chinese_chars / total_chars < 0.3: # 排除纯数字表格行(日期+金额)和邮箱/账号行 if re.match(r'^[\d\.\-\s\|/,]+$', stripped): return None # 纯数字表格行 if '@' in stripped or re.match(r'^[A-Z]{2,4}:', stripped): return None # 邮箱或字段标签 return f"中文占比过低({chinese_chars}/{total_chars}={chinese_chars/total_chars:.0%})" # 3. 常见OCR乱码模式:小写英文碎片+中文混杂 if re.search(r'[a-z]{2,}\s+[a-z]{2,}\s+[a-z]{2,}', stripped) and chinese_chars > 0: return "中英混杂碎片(典型OCR乱码)" # 3b. 日期区域英文字母污染(凤凰文化10.2教训:Se【2024】年【10】月→整段丢失) if re.search(r'[A-Za-z]{2,}\s*【\d{4}】', stripped) and chinese_chars > 0: return "日期区域字母污染(高风险:可能整段条款被OCR吃掉)" # 4. 特殊符号异常密集 special = len(re.findall(r'[^\w\u4e00-\u9fff\s,。、;:""''()【】《》\-\+\.\%\/\|]', stripped)) if special > 5 and total_chars > 0 and special / total_chars > 0.2: return f"异常符号密集({special}个)" return None def main(): if len(sys.argv) < 2: print("用法: python3 ocr-garble-detect.py ") sys.exit(1) filepath = sys.argv[1] with open(filepath, 'r') as f: lines = f.readlines() garbled = [] for i, line in enumerate(lines, 1): reason = is_garbled(line) if reason: garbled.append((i, line.strip()[:80], reason)) if not garbled: print("✅ 未检测到明显乱码行。可以进入Step 2。") else: # 区分真乱码 vs 可能误报(纯数字/邮箱等) real_garble = [g for g in garbled if '无意义英文' in g[2] or '中英混杂' in g[2]] maybe_garble = [g for g in garbled if g not in real_garble] print(f"⚠️ 检测到 {len(garbled)} 处疑似乱码(其中 {len(real_garble)} 处高危)\n") if real_garble: print("🔴 高危乱码(必须vision核实,不核实不进Step2):") for lineno, text, reason in real_garble: print(f" Line {lineno:3d} | {reason}") print(f" | {text}") print() if maybe_garble: print("🟡 疑似乱码(核对数字/格式是否正确):") for lineno, text, reason in maybe_garble: print(f" Line {lineno:3d} | {reason}") print(f" | {text}") print() print(f"--- 高危 {len(real_garble)} 处必须vision核实 + 疑似 {len(maybe_garble)} 处核对数值 ---") print("操作:对每处高危乱码,定位PDF页码 → vision精读 → 记录修正内容") print("全部消灭后才能进入 Step 2。") if __name__ == '__main__': main()