当前位置: 首页 > news >正文

PDF-OCR文件识别篇(三):PDF 切分与表格还原

为什么先讲切分?因为「按表」是整条流水线的最小处理单元。一份 PDF 可能有几十张表,只有先把它拆成一张一张,后面的并行抽取、单表重试、按表注入字段定义才有可能。本章对应包com.example.pdfextraction.pdf

3.1 按表切分PdfTableSlicer

逐页用 PDFBox 提取文本,识别行首形如「表1 …」的标题,把文档切成若干PdfSection

@Component public class PdfTableSlicer { // 表格标题:行首「表 + 数字」,例如「表1 ...」「表 12 ...」 private static final Pattern TABLE_TITLE = Pattern.compile("^\\s*表\\s*\\d+\\b.*"); public List<PdfSection> slice(byte[] pdfBytes) { try (PDDocument document = PDDocument.load(pdfBytes)) { PDFTextStripper stripper = new PDFTextStripper(); stripper.setSortByPosition(true); // 按坐标排序,减少跨栏错乱 // ① 先逐页抽取文本 List<String> pageTexts = 每页 stripper.getText(document); // ② 收集所有「表N」标题出现位置,按归一化标题去重 // ③ 由相邻标题确定每段页范围 } } }

三个关键处理,每一个都对应一类真实坑:

  • 跨页标题去重。跨页表的标题会在每页顶部重复出现。若不处理,同一张表会被切成多段。做法是把标题「去表号 + 去空白」归一化成 key,用Set.add(key)只保留首次出现:
String key = normalizeTitle(t); // 去「表N」前缀与空白 if (StringUtils.isEmpty(key) || !seen.add(key)) continue; // 已见过则跳过
  • 边界页共享。下一张表的标题页,往往同时印着上一张表的尾部(跨页表尾与下表标题同页)。所以相邻两段共享这个边界页,都包含进去,避免漏掉落在该页上半部的尾部数据:
end = (i + 1 < titles.size()) ? titlePages.get(i + 1) : pages; // 截到下一个标题页(含)
  • 可配置大标题切分。除了「表N」,有些章节没有表号但也要单独成段(如「补充说明」)。通过pdf.ai.split-headings配关键词,isConfiguredHeading去掉可选序号前缀(「八、」「9.」)后按关键词匹配: 最终可获取到 八、补充说明 大标题下内容。

本人测试分割文件格式为:

表1 xxxxxx表

表2xxxxx表

八、补充登记信息

九、xxxxx信息

private static final Pattern HEADING_NUM_PREFIX = Pattern.compile("^[一二三四五六七八九十百零\\d]+[、..]\\s*"); private static final int BIG_HEADING_MAX_LEN = 60; // 行太长视为正文,避免误判

切出的每个PdfSection持有:

title // 表格标题 startPage // 起始页 endPage // 结束页 text // 整段合并文本 pageTexts // 逐页文本(供按页分块时附「表头参考」用)

3.2 单表导出PdfSplitter

当走「文件抽取」路径(useFile=true,把单张表 PDF 直接上传给模型让它先解析)时,需要把单张表的页范围导出成独立 PDF。用 PDFBoximportPage实现,落到临时文件,用完即删:

public String splitToTempPdf(byte[] pdfBytes, int start, int end) { try (PDDocument src = PDDocument.load(pdfBytes); PDDocument out = new PDDocument()) { int s = Math.max(1, start), e = Math.min(src.getNumberOfPages(), end); for (int p = s; p <= e; p++) out.importPage(src.getPage(p - 1)); File tmp = File.createTempFile("ai-table-", ".pdf"); out.save(tmp); return tmp.getAbsolutePath(); } } // 调用方在 finally 里 Files.deleteIfExists(tmpPath) 清理

3.4 小结

输入输出用在哪
PdfTableSlicerPDF 字节List<PdfSection>(按表切段)所有路径的第一步
PdfSplitterPDF + 页范围单表临时 PDF 路径文件抽取路径

由于pdf会出现大文件,某个表格就几十近百行。如果一整个文件去执行显然不合适的。故以异步思想,将互不相关的表格和特殊表头对应的数据进行分割,也提高执行效率、准确率。如果你也面临同样的需求,将本文章交给ai,ai会给详细的解释。这里仅提供实现思想😀。

http://www.jsqmd.com/news/1083190/

相关文章:

  • 教育行业AI驱动API安全:从智能识别到一键部署的实践指南
  • Weil-Petersson同胚的离散刻画:Beta和与Epsilon和的几何意义
  • 苍穹外卖【day7|缓存套餐_Spring Cache】
  • ExtractorSharp终极指南:5分钟学会游戏资源编辑与个性化定制
  • 第三:Python-UI自动化框架搭建(关键字驱动)
  • 吊牌质检一秒要处理50张图?我用了这3招
  • KMS_VL_ALL_AIO:Windows与Office批量激活的终极技术解析与实战指南
  • Notion 收购 Skiff 推邮件客户端又关闭,超半数用户靠 AI 管邮件!
  • 3步掌握Box64:让ARM设备运行x86_64程序的终极指南
  • 美国风投寒冬:独角兽变“僵尸”,5000亿到1万亿美元名义价值将蒸发?
  • 一个只能查自己、不能查别人的学术检测系统,藏着什么小心思?
  • 从一份行业白皮书看消费决策的“信息透明化”趋势
  • Bootstrap:前端开发框架
  • 机器人非抓取操作与CI-MPC控制技术解析
  • AssetRipper终极指南:从Unity游戏资源提取到项目复用的完整解决方案
  • STM32调试接口设计问题与解决方案
  • Sunshine自托管游戏串流:如何实现毫秒级低延迟的跨平台云游戏体验
  • 小米MiMo邀请码最新(2026.07)
  • 终极指南:3步轻松实现《命运2》单人游戏体验的完整解决方案
  • 智能视觉系统API自动化测试实战:从方案设计到CI/CD集成
  • 深度伪造革命:roop-unleashed如何重塑AI换脸技术边界
  • 如何专业修复联发科设备变砖:MTKClient终极恢复指南
  • 纯go语言ui框架之高级组件echart系列:第59到83个组件
  • 成熟稳定商用级云PACS完整源码,开箱即可部署上线,基于Spring Boot 3.5 + Java 17+Vue 3构建
  • 3步快速搭建你的专属云游戏服务器:Sunshine完整指南
  • Linux 5.10 总线机制与故障排查详解
  • Beyond Compare 5授权机制深度解析:3种技术路径实现自定义密钥生成
  • 从零开始:3步搭建你的私人游戏串流服务器
  • Dev C++ 6.5下载免费版 C++编译器安装图解(2026最新)
  • 基于CSK6与AIUI的智能风扇语音控制方案