OCR 表格跨页时如何合并同一列字段
来源:17golang原创
时间:2026-09-15 06:14:16 145浏览 收藏
我第一次处理跨页 OCR 表格时,最容易误判的是“每一页识别得都对,合并后自然也会对”。实际情况正好相反:OCR 往往按页返回表格,下一页会重新识别表头,跨页的长文本还可能被切成两个单元格。要合并同一列字段,核心不是把两段字符串拼起来,而是先确认它们属于同一张表,再用稳定的列位和行关系重建记录。
可靠的做法是保留页码、行列坐标、单元格跨度和置信度;先做“同表判断”,再做列位归一化,最后过滤重复表头并对跨页断行做单独标记。
- 页面相邻不等于同一张表,表头签名和横向范围要一起判断。
- 统一列位时使用列锚点,不要用每页 OCR 返回数组的下标硬拼。
- 合并后检查列数、表头次数、行序和低置信度单元格。
为什么每页识别正确,合并后却会错列
表格识别结果通常带有页面归属和单元格几何信息。以常见布局接口为例,表格单元格会提供 rowIndex、columnIndex,有的还会提供 rowSpan、columnSpan。它们描述的是“本页表格中的位置”,不是整份 PDF 的全局行号。若直接把第 2 页的第 0 行接到第 1 页的最后一行,重复表头会被当成数据;若按数组顺序拼接,某个漏检单元格又会让后续列整体右移。

先把每页结果整理成统一中间结构,至少保存这些字段:
| 字段 | 作用 | 缺失时的风险 |
|---|---|---|
| page | 定位原始页 | 无法回溯错位来源 |
| rowIndex / columnIndex | 表达页内网格位置 | 无法建立列位 |
| rowSpan / columnSpan | 保留合并单元格语义 | 长字段可能被错误拆散 |
| bounding box | 比较横向范围与列锚点 | 只能依赖脆弱的文本顺序 |
先判断下一页是不是同一张表
我会把“同表判断”单独做成一个结果,而不是在遍历页面时顺手决定。相邻页只是候选条件,至少再比较四项:列数量是否接近、表格左右边界是否接近、表头文本签名是否相同或为空、下一页顶部是否紧接上一页的表格区域。若页面中间出现新的标题、合计行或明显不同的列模式,就应该结束当前表。
重复表头不要简单按固定字符串删除。更稳的是把表头单元格归一化后生成签名,例如去空白、统一全角半角,再比较列位和文本。表头签名相同且位于下一页顶部时,标记为 repeat_header;签名不同但列锚点相同的行,可能是多级表头,应保留并交给业务规则判断。
先统一列位,再合并同一列字段
列位归一化的关键是“横向位置优先、页内索引兜底”。可以取第一页稳定表头或高置信度数据行的 x 中心点作为列锚点,然后将后续单元格分配到最近的锚点。分配时要设置最大距离;超过阈值的单元格不要强行塞进某列,而是进入待复核集合。
def merge_pages(page_tables, max_x_distance=24):
# 先按页码保留表格边界,避免把不同表格直接串在一起。
schema = build_column_schema(page_tables[0])
merged_rows = []
for table in page_tables:
# 重复表头只跳过当前行,不删除正文中的同名字段。
for row in table.rows:
if is_repeated_header(row, schema):
continue
# 依据单元格中心点映射到统一列位,不能只使用 columnIndex。
cells = map_cells_to_schema(row.cells, schema, max_x_distance)
if cells.unmatched:
# 记录页码和原坐标,留给人工或规则二次判断。
row.review_reason = "column-anchor-mismatch"
merged_rows.append(cells)
# 只在列数、表头次数和行序检查通过后输出业务记录。
return validate_and_mark(merged_rows, schema)

跨页断行要和普通新行区分开。可以使用“上一页最后一行的目标列未闭合、下一页首行横向位置匹配、两段文本拼接后符合字段类型”三个信号。只有满足规则时才合并文本,并保留 continued_from_page 之类的来源标记;金额、日期和编号字段不要因为看起来能拼接就自动合并。
合并结果怎样验证
验证不需要重新识别整份文件,抽取跨页边界附近的样本即可。第一项检查每条记录的列数是否等于统一列模式;第二项统计重复表头是否只出现在页面顶部且未进入数据;第三项比较页末和页首的行序,确认没有跳行或重复;第四项检查低置信度与未匹配列,确保它们被标记而不是静默丢失。
如果使用支持表格结构的文档 AI 服务,还要确认返回的是结构化单元格而不是只有纯文本。服务文档通常会明确页面、表格、单元格及跨度字段的层级;跨页表格是否自动聚合则取决于具体模型,不能把某一产品的行为当成通用 OCR 规则。
常见问题
只比较相邻页可以吗?
不建议。中间可能插入脚注、合计页或新的表格;相邻关系只能生成候选,列模式和表头签名才是主要证据。
没有 bounding box 还能合并吗?
可以先用 columnIndex 和表头文本做保守合并,但要把置信度降级。没有几何信息时,不应自动处理列数变化和复杂合并单元格。
重复表头应该全部删除吗?
只删除被判定为页面续表表头的行。多级表头、业务字段名和正文中恰好相同的文本,应保留原始行并交给规则判断。
跨页 OCR 的难点不在“把文本拼到一起”,而在保存页面证据后重建表格语义。把同表判断、列位归一化、断行处理和结果校验拆开,后续换 OCR 引擎时也只需要适配输入层。
-
273 收藏
-
284 收藏
-
387 收藏
-
328 收藏
-
426 收藏
-
科技周边 · 人工智能 | 2小时前 | 人工智能 · rag · 向量检索 · 检索增强生成 · rerank · 向量数据库 metadata filter 向量检索过滤条件 rerank顺序 RAG检索409 收藏
-
科技周边 · 人工智能 | 3小时前 | 上下文管理 · 向量检索 · AI工程 · RAG实践 · 文档切片 · chunk overlap RAG文档切片 RAG重叠窗口 上下文膨胀 向量检索召回238 收藏
-
科技周边 · 人工智能 | 4小时前 | API · 人工智能 · 结构化输出 · 函数调用 · Responses API Structured Outputs function_call_output111 收藏
-
312 收藏
-
111 收藏
-
356 收藏
-
403 收藏
-
120 收藏
-
457 收藏
-
449 收藏
-
383 收藏
-
科技周边 · 人工智能 | 16小时前 | 人工智能 · openai api · 工程实践 · 批处理 · OpenAI Batch API custom_id 批量请求结果映射 JSONL 结果回配105 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习