AI 读 Word 表格总读错?先查合并单元格和表头这 3 处

AI 读 Word 表格总读错?先查合并单元格和表头这 3 处

上周帮朋友处理一份 18 页的项目验收文档,里面有 11 张表。我让模型把「设备清单」抽成 JSON,字段名都对,行数总少两行。把同一页截图发过去,它又能读对。

问题不在模型,在我喂进去的文本:表格一转换,合并单元格把列号顶歪了,后面每一行的值都跟着错位。

先确认表格是不是「矩形」

python-docx 读表格很快,但它不会告诉你这张表是不是规整的。先打印前几行,看竖线数量:

python 复制代码
from docx import Document

doc = Document("验收文档.docx")
for ti, tbl in enumerate(doc.tables):
    print("table", ti, "rows", len(tbl.rows), "cols", len(tbl.columns))
    for row in tbl.rows[:3]:
        cells = [c.text.strip().replace("\n", " ") for c in row.cells]
        print(len(cells), " | ".join(cells))

如果某一行的 len(cells) 和其他行不一样,或者第一行只有一列、文字却横跨整页,基本可以判定有合并单元格。此时按位置取列,一定会错。

合并单元格会重复返回同一个单元格

Word 里横向合并(gridSpan)和纵向合并(vMerge)在 python-docx 里表现不同:横向合并后,row.cells 会把同一个单元格对象重复返回;纵向合并后,被合并的位置可能返回空文本。两种情况下,cells[3] 都不再等于「第 4 列」。

我的处理顺序是:

  1. 先读出 len(tbl.columns) 作为目标列数;
  2. 逐行遍历,遇到数量不足就补空字符串,遇到重复对象就跳过;
  3. 把纵向合并的值向下填充,直到下一个非空值出现。
python 复制代码
target = len(tbl.columns)
rows = []
for row in tbl.rows:
    vals, seen = [], set()
    for c in row.cells:
        key = id(c._tc)
        if key in seen:
            continue
        seen.add(key)
        vals.append(c.text.strip())
    while len(vals) < target:
        vals.append("")
    rows.append(vals[:target])

这段代码不优雅,但能把大部分「列错位」挡住。真正复杂的表,比如带斜线表头、跨页续表,我会直接放弃自动转换,改成人工确认后再喂给模型。

表头不一定在第一行

很多正式文档的表格第一行是标题,横跨所有列,比如「表 3-1 设备清单」。真正的字段名在第二行。如果直接把第一行当表头,模型拿到的字段名会全部变成「表 3-1 设备清单」。

我的判断方法:从上往下找第一行「非空单元格数量等于列数」的行,把它当表头;如果前一行只有一格,就把它当表标题单独存起来。这样后面做字段映射时,不会把标题误当字段。

转成 Markdown 后,对三个数

表格转成 Markdown 之后,我会先做一次不依赖模型的复核:

  • 行数:Markdown 的行数是否等于 len(tbl.rows);
  • 列数:每行 | 分隔后的段数是否一致;
  • 合计:如果原表有「合计」行,把数值列加一遍,看是否等于原表合计。

三个数里有一个对不上,就不把这张表交给模型。因为一旦行列错位,模型会把错误的值编得很合理,人工反而更难发现。

提交前我会看的 5 个点

  • 表格是否为矩形,有没有某一行少列;
  • 表头行是否唯一,表标题有没有被当成字段名;
  • 合并单元格是填平还是跳过,规则是否写进了脚本;
  • 数值列的单位是否保留(元 / 万元最容易丢);
  • 脚注和「续表」有没有被截断。

这套检查不复杂,但我现在每次处理带表格的文档都会先跑一遍。模型读错表格,十有八九不是理解能力问题,而是输入在转换阶段就已经变形了。

相关推荐
我登哥MVP18 分钟前
DeepSeek-Harness-Super-Agent-学习笔记
人工智能·深度学习·神经网络·机器学习·自然语言处理·agent
LucianaiB26 分钟前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
apcipot_rain34 分钟前
C++转Java日记(03)
java·开发语言·c++
布莱克60541 分钟前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
xys_6781 小时前
深挖C++:类和对象(中)
开发语言·c++
灿飞屋1 小时前
Rust 编程其实很简单
开发语言·rust
冬奇Lab2 小时前
一天一个开源项目(第256篇):Anatomy —— 让 Claude 为技术概念「发明一台机器」,画成可交互的等距插画
人工智能·开源
孟郎郎2 小时前
打造一切(Craft Anything)——克隆构造世间万物
人工智能·ai·github·软件构建·开源软件
Martina_03212 小时前
AI生成3D场景的霓虹灯一开就糊成光团?用6步检查Emissive、Bloom与曝光
人工智能·3d·ai·自然语言处理·游戏引擎·材质·贴图