同一份 PPT 为什么会比较出颜色变化:一次对象身份配对实测
比较工具最基本的要求,是同一个输入与自身比较时,不应凭空产生内容修改。今天在检查一个 PPTX 差异工具时,我构造了一页只有两个矩形的幻灯片,发现即使前后读取的是同一个文件,报告仍然给出了两条方向相反的填充色变化。这篇文章记录复现方法、控制组和配对边界,不把诊断冒充完整修复。
从“有没有变化”转向“比较的是谁”
这页幻灯片没有图片、表格、外部链接或真实业务内容。两个矩形的显示名都设为 SharedName,文本相同,一个填充蓝色,另一个填充橙色。python-pptx 给它们分配的 shape_id 分别为 2 和 3。
测试程序保存一次 same.pptx,再让项目的解析器读取这个文件两次。两份 SlideContent.to_dict() 完全相等,因此这不是文件另存、格式转换或编辑器渲染产生的差异。共享比较器却报告了蓝色变橙色、橙色变蓝色。
这意味着比较器很可能找错了对象。对比两个对象的属性之前,必须先回答:旧版本中的这个对象,对应新版本中的哪一个对象?显示名看起来像一个方便的键,但输入数据没有因此自动获得唯一性保证。
为什么必须保留控制组
单独看到一个失败样例,不能立即断言是名字重复造成的。我又构造了两组同文件自比较:第一组保留不同颜色,但把名字改成 Shape0、Shape1;第二组保留相同名字,但把两个颜色改成相同。
| 场景 | modified 页数 | 原始样式变化条目 |
|---|---|---|
| 不同名字、不同颜色 | 0 | 0 |
| 相同名字、相同颜色 | 0 | 0 |
| 相同名字、不同颜色 | 1 | 2 |
环境使用 python-pptx 1.0.2,上游版本为 db6c75892650854abf663c91b66ead486fde1299。这里 summary.style_changes 统计的是发生变化的页数,不能把它误读为具体变化条目数。原始列表才展示了两条不存在的修改。
控制组还显示一个独立的旧问题:没有内容变化的页面被标成 moved。它已经有 Issue #16,因此本次没有把这个现象再次当成新问题。定位缺陷时,应该比较原始字段和具体差异,不能只盯着总状态。
双重循环怎样制造不存在的变化
共享比较函数对旧形状和新形状做双重循环,只要 name 相同就比较样式,没有记录某个新对象是否已经匹配过。于是两个同名对象形成四组配对:A 对 A、A 对 B、B 对 A、B 对 B。两个正确的自配对没有差异,两个错误的交叉配对却各自产生一条颜色变化。
下面是独立于 PPT 库的最小演示,方便检查配对逻辑。数据均为手工构造:
rows = [
{"id": 2, "name": "SharedName", "fill": "blue"},
{"id": 3, "name": "SharedName", "fill": "orange"},
]
false_pairs = [
(a["id"], b["id"])
for a in rows for b in rows
if a["name"] == b["name"] and a["fill"] != b["fill"]
]
assert false_pairs == [(2, 3), (3, 2)]
两个“变化”刚好方向相反,是值得追查匹配关系的线索。类似错误也可能出现在用商品名合并订单、用文件显示名关联资源或用标题配对文档的程序中。名字相同只能作为候选条件,不能自动等同于对象身份相同。
一对一配对需要哪些约束
最直接的改进方向是先建立映射,再比较属性,而不是一边遍历一边随意配对。对于已知身份稳定的输入,可以使用唯一 ID;构建索引时必须检查缺失和重复,不能用字典覆盖来悄悄丢掉对象。
但这不意味着把 name 换成 shape_id 就完成了通用修复。不同软件重新导出 PPT 后,ID 是否保持稳定需要单独验证;当前解析模型也没有保留 shape_id。可靠实现需要明确作用范围,定义候选匹配、唯一性检查、未匹配对象和歧义对象的输出方式。出现歧义时,宁可显示“无法唯一配对”,也不应该生成看似确定的颜色修改。
我为文章另外写了一个仅用于演示的稳定 ID 比较函数,并运行了四项检查:复现交叉配对、同文件比较无变化、只改一个对象时只返回一条真实变化、重复 ID 输入明确失败。这证明演示代码的行为,不能证明整个 PPT 工具已经修复;本次没有修改上游代码。
回归用例与报告方式
后续修复至少应覆盖两种名字唯一性、两种样式相同性,并加入只改变一个对象、增删对象、顺序变化、ID 重编号和歧义匹配。将配对结果与属性差异分开断言,才能知道失败来自“没找到对应对象”还是“比较字段不完整”。
最终报告也应区分页级统计和对象级证据。页数适合概览,具体对象、旧值、新值和匹配依据才适合复核。只修正总计数字,或者隐藏方向相反的两条记录,都会把真正的配对错误留在程序里。
完整合成复现已提交到 PPT-diff Issue #41。材料没有业务文件和个人信息。先用自比较与控制组证明问题,再讨论如何修复,比仅凭一张异常截图更容易让维护者复现和判断影响范围。
- 点赞
- 收藏
- 关注作者
评论(0)