使用PyPDF2+re定位PDF页码时重复匹配导致tabula提表错误
问题根因
出现该问题有三个核心原因:
- 子串误匹配:短目标串
STATEMENT OF PROFIT AND LOSS是长目标串CONSOLIDATED STATEMENT OF PROFIT AND LOSS的子串,遍历到第131页时,长串内容会触发短串的匹配规则 - 变量无保护:匹配到对应页码后没有终止对应项的匹配逻辑,第131页的误匹配会覆盖第73页已经存入
sat变量的正确值 - 逻辑错误:原代码打印S对应页码时错误使用了
i+1,和标注的S实际在131页的位置不符
修复方法
按以下逻辑调整代码即可:
- 初始化变量时增加命中标记,两个目标串只要找到对应页码,就不再更新对应存储变量,防止值被覆盖
- 调整匹配顺序,优先匹配长度更长的目标串S,当前页命中S后直接跳过P的匹配判断,从逻辑上避免子串误触发
- 两个目标都命中后直接终止PDF遍历,不需要扫描剩余页面,提升运行效率
- 提取表格时分别输出两个页面对应的文件,避免结果覆盖
修复后完整代码
import tabula import PyPDF2 import re pdffile = "NCC.pdf" reader = PyPDF2.PdfFileReader(pdffile) P = "STATEMENT OF PROFIT AND LOSS" # 实际位于PDF第73页 S = "CONSOLIDATED STATEMENT OF PROFIT AND LOSS" # 实际位于PDF第131页 # 初始化页码存储变量和命中标记 sat = None con = None found_p = False found_s = False for i, page in enumerate(reader.pages, start=1): # 两个目标都找到就终止遍历 if found_p and found_s: break text = page.extract_text() # 优先匹配更长的目标串S if not found_s and re.search(re.escape(S), text): print(f"S String Found on Page: {i}") con = str(i) found_s = True # 命中长串后跳过当前页P的匹配,避免子串误判 continue # 仅在未找到P时执行匹配 if not found_p and re.search(re.escape(P), text): print(f"P String Found on Page: {i}") sat = str(i) found_p = True # 校验页码存在后再执行提取,避免空值报错 if sat: tabula.convert_into(pdffile, "profit_loss.csv", output_format="csv", pages=sat) if con: tabula.convert_into(pdffile, "consolidated_profit_loss.csv", output_format="csv", pages=con)
补充:如果PDF其他位置还存在零散的子串误匹配,可以给匹配规则增加边界限制,比如将P的匹配条件改为
re.search(rf"(?<!\S){re.escape(P)}(?!\S)", text),保证匹配到的目标串前后是空白字符或行首行尾,进一步提升匹配准确率。
内容的提问来源于stack exchange,提问作者Shashi
相关产品推荐
相关产品推荐

