From 5f3df306c22c13260daccb74aa12b8d22d7b9b5c Mon Sep 17 00:00:00 2001 From: xiaoxue_admin <9283713@qq.com> Date: Mon, 22 Jun 2026 12:11:58 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=91=E7=9B=AE=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E8=A1=A5=E4=BD=8D=20+=20=E6=91=98=E8=A6=81=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E7=A7=91=E7=9B=AE=E5=90=8D=E7=A7=B0=20-=20=E7=A7=91=E7=9B=AE?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B2=A1=E5=90=8D=E7=A7=B0=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E4=BB=8E=E4=B8=8B=E6=96=B9200px=E5=86=85=E8=A1=A5=E5=8F=96?= =?UTF-8?q?=E5=90=AB=E4=B8=AD=E6=96=87=E7=9A=84=E6=96=87=E6=9C=AC=E4=BD=9C?= =?UTF-8?q?=E4=B8=BA=E5=90=8D=E7=A7=B0=20-=20=E6=91=98=E8=A6=81=E5=80=99?= =?UTF-8?q?=E9=80=89=E6=8E=92=E9=99=A4=E4=BB=A5-/=EF=BC=8D=E5=BC=80?= =?UTF-8?q?=E5=A4=B4=E7=9A=84=E4=BC=9A=E8=AE=A1=E7=A7=91=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E6=9C=AC=20-=20=E6=91=98=E8=A6=81=E5=80=99=E9=80=89=E6=8E=92?= =?UTF-8?q?=E9=99=A4=E4=B8=8E=E4=BB=A3=E7=A0=81=E5=90=8D=E7=A7=B0=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=E5=80=99=E9=80=89=20-=20=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E8=A1=A5=E4=BD=8D=E6=8E=92=E9=99=A4=E5=90=AB=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E7=A7=91=E7=9B=AE=E4=BB=A3=E7=A0=81=E7=9A=84=E8=A1=8C=EF=BC=88?= =?UTF-8?q?=E9=98=B2=E8=AF=AF=E5=8C=B9=E9=85=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/parser.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/core/parser.py b/core/parser.py index c3caaae..869179d 100644 --- a/core/parser.py +++ b/core/parser.py @@ -178,6 +178,41 @@ class K3VoucherParser: if not codes: return self._parse_entries_fallback() + # === 4.3 科目名称补位:如果代码没有名称,从附近行找 === + for code in codes: + if code['name']: # 已有名称则跳过 + continue + # 在当前代码下方附近找包含中文的文本(排除含其他科目代码的行) + name_candidates = [] + for text, conf, cx, cy, box in self.lines: + if conf < 0.5: + continue + if not re.search(r'[\u4e00-\u9fff]', text): # 必须含中文字 + continue + if any(k in text for k in skip_keywords + ['合计', '亿', '千', '百', '拾', '万']): + continue + if re.match(r'^[\d.\-,]+$', text.strip()): + continue + if len(text.strip()) < 3: + continue + if cx < 400 or cx > 1300: # 名称列通常在x=400-1300 + continue + if re.search(r'(公司|有限|集团|企业)', text): # 排除公司名 + continue + if text.strip() in ('未到账', '已到账', '未达', '已达'): + continue + # 排除包含其他科目代码的行(如 "6603.02-财务费用") + if re.search(r'\d{3,}\.\d', text): + continue + dist_y = cy - code['y_pos'] + if 0 < dist_y < 200: # 代码下方200px以内 + name_candidates.append((text, dist_y, cx, cy)) + if name_candidates: + # 取y距离最近的 + name_candidates.sort(key=lambda x: (x[1], -x[2])) + code['name'] = name_candidates[0][0] + code['y_pos'] = max(code['y_pos'], name_candidates[0][3]) # 更新y为名称位置 + # === 4.5 摘要提取:从剩余 OCR 文字中找摘要 === code_y_min = min(c['y_pos'] for c in codes) @@ -218,6 +253,13 @@ class K3VoucherParser: continue if text.strip() in ('未到账', '已到账', '未达', '已达'): continue + # 过滤垃圾摘要:纯字母数字/太短/无中文 + if not re.search(r'[\u4e00-\u9fff]', text): # 没有中文字,排除 + continue + if len(text.strip()) < 4: # 太短 + continue + if conf < 0.6: # 提高置信度要求 + continue # 过滤非摘要的日期/期号文本 if re.match(r'\d{3}年第\d+期', text.strip()): continue @@ -233,6 +275,23 @@ class K3VoucherParser: # 过滤包含"公司"、"物业"、"有限"等公司相关词 if re.search(r'(公司|有限|物业|集团|企业)', text): continue + # 过滤科目名称文本:以 -/- 开头的会计科目 + if re.match(r'^[--][^\d]', text.strip()) and any( + kw in text for kw in ['银行', '货币', '账款', '费用', '收入', '成本', + '应收', '应付', '预付', '预收', '其他', '库存', + '管理', '财务', '手续费', '押金', '资本'] + ): + continue + # 过滤纯科目名称(在代码附近找到的科目名不应作为摘要) + if len(text.strip()) < 20: # 短文本更容易是科目名 + is_near_name = False + for c in codes: + if c['name'] and c['name'] in text: + if abs(c['y_pos'] - cy) < 100: + is_near_name = True + break + if is_near_name: + continue if cy < desc_upper_bound: continue # 去重:跳过 y 距离 < 30 的重复文本