答案卷抬头信息改为一行一项:修复长学院名与右侧字段重叠 #22

Closed
opened 2026-10-29 14:51:33 +00:00 by laoyang · 1 comment
Owner

答案卷抬头信息改为一行一项:修复长学院名与右侧字段重叠

用户诉求

用户原话:「试卷里面的答案和评分标准有问题,评分标准最开始不是有个表格吗,
里面有开课学院什么的,如果学院名字太长,就和后面课程名称重合在一起了。
看看怎么解决。我建议一行一个信息,因为这个又不怕长,如果太长,
一行都放不下,就直接换行,这样应该就没有问题了。」

现象(已复现并量化)

把 dept 改成超长值
计算机科学与技术学院(人工智能与大数据技术方向实验班) 后,
pymupdf 提取成品 PDF 的 span 坐标:

y=139.5  开课学院:(70.87~123.37)   值:(123.37~406.87)

而按 \makebox[0.3333\linewidth] 的布局,第二格「课程名称」本该从
216.0 开始 —— 值一直排到 406.87,重叠 190.87bp,
把「课程名称 / 试卷类型」整个压住了。

⚠️ 关键:编译不报任何错误,也没有 Overfull 警告(rc=0 over=0)。
\makebox 固定盒宽,内容超出时只是"溢出盒外"继续排,
TeX 不认为这是坏行。⇒ 这个 bug 只能靠看渲染结果或量 span 坐标发现,
看日志发现不了。

根因

ouckey.sty 第 240 行 \ouckey@inforow:

\newcommand{\ouckey@inforow}[6]{%
  \par\noindent
  \makebox[0.3333\linewidth][l]{\ouckey@cell{#1}{#2}}%
  \makebox[0.3333\linewidth][l]{\ouckey@cell{#3}{#4}}%
  \makebox[0.3333\linewidth][l]{\ouckey@cell{#5}{#6}}\par}

\makebox[固定宽][l] 是不可断的盒子:

  • 内容比盒宽短 → 左对齐,右侧留白(正常)
  • 内容比盒宽长 → 直接溢出盒外,压到右边一格上(本次问题)
  • 盒内的中文不能换行(\makebox 内部是 LR 模式,不做段落断行)

所以三格布局对"短字段"友好,对"长字段"必然重叠。

方案:改为一行一项

\newcommand{\ouckey@inforow}[2]{%
  \par\noindent\textbf{#1:}#2\par}

即每项独占一行,用普通段落排版 —— 超长自动换行,不再有固定盒宽的假设。

为什么这个方案对

  1. 彻底消除重叠:没有并排,就不存在互相压住。
  2. 长字段自然换行:\par 模式下中文可在任意汉字间断行。
  3. 读者友好:抬头信息是"查阅"性质,一项一行比三格更容易扫读。
  4. 符合用户直觉:用户原话「这个又不怕长」。

代价(已接受)

抬头从 3 行变成 9 行(开课学院 / 课程名称 / 试卷类型 / 学生学院 /
年级专业 / 考试方式 / 任课教师 / 命题人 / 满分),多占约 6 行高度。
答案卷是 A4、内容不满页,多 6 行不影响版面。

留空的项仍自动不印(\ouckey@ifempty 逻辑不变),所以实际行数随填写项变化。

验收标准

  1. 用超长 dept(含括号说明)编译,抬头各字段无重叠:
    逐行检查 span 的 x 区间不交叠
  2. 超长字段自动换行,不超出右边界
  3. 正常长度时抬头仍整齐(一项一行)
  4. 留空项不印、不留空行
  5. 编译 error 0 / Overfull 0,页数不变(3 页)
  6. 两套 TeX(2022 / 2025)结果一致

备份

示例文件已备份到 /tmp/keybase.tex(WSL 内),改完可比对。

答案卷抬头信息改为一行一项:修复长学院名与右侧字段重叠 ## 用户诉求 用户原话:「试卷里面的答案和评分标准有问题,评分标准最开始不是有个表格吗, 里面有开课学院什么的,如果学院名字太长,就和后面课程名称重合在一起了。 看看怎么解决。我建议一行一个信息,因为这个又不怕长,如果太长, 一行都放不下,就直接换行,这样应该就没有问题了。」 ## 现象(已复现并量化) 把 `dept` 改成超长值 `计算机科学与技术学院(人工智能与大数据技术方向实验班)` 后, pymupdf 提取成品 PDF 的 span 坐标: ``` y=139.5 开课学院:(70.87~123.37) 值:(123.37~406.87) ``` 而按 `\makebox[0.3333\linewidth]` 的布局,第二格「课程名称」本该从 **216.0** 开始 —— 值一直排到 406.87,**重叠 190.87bp**, 把「课程名称 / 试卷类型」整个压住了。 ⚠️ 关键:**编译不报任何错误,也没有 Overfull 警告**(rc=0 over=0)。 `\makebox` 固定盒宽,内容超出时只是"溢出盒外"继续排, TeX 不认为这是坏行。⇒ 这个 bug 只能靠看渲染结果或量 span 坐标发现, 看日志发现不了。 ## 根因 `ouckey.sty` 第 240 行 `\ouckey@inforow`: ```latex \newcommand{\ouckey@inforow}[6]{% \par\noindent \makebox[0.3333\linewidth][l]{\ouckey@cell{#1}{#2}}% \makebox[0.3333\linewidth][l]{\ouckey@cell{#3}{#4}}% \makebox[0.3333\linewidth][l]{\ouckey@cell{#5}{#6}}\par} ``` `\makebox[固定宽][l]` 是**不可断的盒子**: - 内容比盒宽短 → 左对齐,右侧留白(正常) - 内容比盒宽长 → **直接溢出盒外,压到右边一格上**(本次问题) - 盒内的中文**不能换行**(`\makebox` 内部是 LR 模式,不做段落断行) 所以三格布局对"短字段"友好,对"长字段"必然重叠。 ## 方案:改为一行一项 ```latex \newcommand{\ouckey@inforow}[2]{% \par\noindent\textbf{#1:}#2\par} ``` 即每项独占一行,用普通段落排版 —— 超长自动换行,不再有固定盒宽的假设。 ### 为什么这个方案对 1. **彻底消除重叠**:没有并排,就不存在互相压住。 2. **长字段自然换行**:`\par` 模式下中文可在任意汉字间断行。 3. **读者友好**:抬头信息是"查阅"性质,一项一行比三格更容易扫读。 4. **符合用户直觉**:用户原话「这个又不怕长」。 ### 代价(已接受) 抬头从 3 行变成 9 行(开课学院 / 课程名称 / 试卷类型 / 学生学院 / 年级专业 / 考试方式 / 任课教师 / 命题人 / 满分),多占约 6 行高度。 答案卷是 A4、内容不满页,多 6 行不影响版面。 留空的项仍自动不印(`\ouckey@ifempty` 逻辑不变),所以实际行数随填写项变化。 ## 验收标准 1. 用超长 `dept`(含括号说明)编译,抬头各字段**无重叠**: 逐行检查 span 的 x 区间不交叠 2. 超长字段自动换行,不超出右边界 3. 正常长度时抬头仍整齐(一项一行) 4. 留空项不印、不留空行 5. 编译 error 0 / Overfull 0,页数不变(3 页) 6. 两套 TeX(2022 / 2025)结果一致 ## 备份 示例文件已备份到 `/tmp/keybase.tex`(WSL 内),改完可比对。
Author
Owner

已完成,提交 42c1394

按你的建议改为「一行一项」

现在抬头是这样:

课程名称:数字逻辑
开课学院:计算机科学与技术学院
学生学院:信息科学与工程学院
年级专业:计算机科学与技术专业 2023 级
试卷类型:A 卷
考试方式:闭卷、笔试
任课教师:张远航
命题人:张远航
满分:100 分

超长字段自动换行,第二行缩进对齐(从标签后开始,不是顶格)。

根因

\ouckey@inforow 用三个 \makebox[0.3333\linewidth][l] 并排。\makebox
是不可断的盒子:

  • 内容比盒宽短 → 左对齐(正常)
  • 内容比盒宽长 → 直接溢出盒外,压到右边一格(就是你说的重叠)
  • 盒内中文不能换行(LR 模式,不做段落断行)

三格布局对短字段友好,对长字段必然重叠。

⚠️ 这个 bug 编译不报任何错,也没有 Overfull 警告。\makebox 内容溢出
盒外时 TeX 不认为是"坏行"。所以光看日志发现不了,只能量坐标 ——
实测超长时重叠 190.87bp,把「课程名称 / 试卷类型」整个压住。

三种情况都验证过

场景 结果
正常(学院名 12 字) 9 项齐全,无重叠
长(含括号说明,约 40 字) 单行排到 x=406.90,无重叠(下面没有格子可压)
极长(约 70 字) 自动换行两行,第二行缩进对齐,右缘正好 524.40
留空(dept/college/major 全空) 三项整项不印,不留空行

附带修掉一个旧版就有的 bug

留空项会印出孤立的「开课学院:」,后面没值。 这是旧版就有的问题,
三格布局下不明显,改成一行一项后暴露。

根因:旧判空宏 \ouckey@ifempty{\ouckey@dept} 里 \detokenize 不展开
参数
,看到的是字符串 \ouckey@dept(宏名本身),永远非空 ⇒ 判空永远失败。

修法:在 \define@key 里就规范化空值,13 个 key 全改走
\ouckey@setkey。

⚠️ 中途试过「先 \edef 展开再 \detokenize」,报 ! Incomplete \iffalse
—— \if...\else...\fi 被 \expandafter 链打散,TeX 匹配 \fi 错位。
这类宏层展开的修补太脆,放弃了,改用规范化存值的路子。

验证

试卷题型示例        6 页  err=0 over=0  (未受影响)
参考答案与评分标准  4 页  err=0 over=0
全库                13/13 通过

示例文件测试后已还原,git diff 为空。只改 ouckey.sty 一个文件。

关于页数

3 页 → 4 页。抬头从 3 行变 9 行,这是「一行一项」的必然代价。
你已确认接受。 第 4 页只有说明文字末尾 2 行 + 签字行。

行距我收紧到了 15bp(正文是 16bp)—— 抬头是查阅信息,不需要正文行距,
9 行省了约 52bp,相当于 3 行正文的空间。

## 已完成,提交 `42c1394` ### 按你的建议改为「一行一项」 现在抬头是这样: ``` 课程名称:数字逻辑 开课学院:计算机科学与技术学院 学生学院:信息科学与工程学院 年级专业:计算机科学与技术专业 2023 级 试卷类型:A 卷 考试方式:闭卷、笔试 任课教师:张远航 命题人:张远航 满分:100 分 ``` 超长字段自动换行,第二行**缩进对齐**(从标签后开始,不是顶格)。 ### 根因 `\ouckey@inforow` 用三个 `\makebox[0.3333\linewidth][l]` 并排。`\makebox` 是**不可断的盒子**: - 内容比盒宽短 → 左对齐(正常) - 内容比盒宽长 → **直接溢出盒外,压到右边一格**(就是你说的重叠) - 盒内中文**不能换行**(LR 模式,不做段落断行) 三格布局对短字段友好,对长字段必然重叠。 ⚠️ **这个 bug 编译不报任何错,也没有 Overfull 警告**。`\makebox` 内容溢出 盒外时 TeX 不认为是"坏行"。所以光看日志发现不了,只能量坐标 —— 实测超长时重叠 190.87bp,把「课程名称 / 试卷类型」整个压住。 ### 三种情况都验证过 | 场景 | 结果 | |---|---| | 正常(学院名 12 字) | 9 项齐全,无重叠 | | 长(含括号说明,约 40 字) | 单行排到 x=406.90,无重叠(下面没有格子可压) | | **极长(约 70 字)** | **自动换行两行,第二行缩进对齐,右缘正好 524.40** | | 留空(dept/college/major 全空) | 三项**整项不印**,不留空行 | ### 附带修掉一个旧版就有的 bug **留空项会印出孤立的「开课学院:」,后面没值。** 这是旧版就有的问题, 三格布局下不明显,改成一行一项后暴露。 根因:旧判空宏 `\ouckey@ifempty{\ouckey@dept}` 里 `\detokenize` **不展开 参数**,看到的是字符串 `\ouckey@dept`(宏名本身),永远非空 ⇒ 判空永远失败。 修法:在 `\define@key` 里就规范化空值,13 个 key 全改走 `\ouckey@setkey`。 ⚠️ 中途试过「先 `\edef` 展开再 `\detokenize`」,报 `! Incomplete \iffalse` —— `\if...\else...\fi` 被 `\expandafter` 链打散,TeX 匹配 `\fi` 错位。 这类宏层展开的修补太脆,放弃了,改用规范化存值的路子。 ### 验证 ``` 试卷题型示例 6 页 err=0 over=0 (未受影响) 参考答案与评分标准 4 页 err=0 over=0 全库 13/13 通过 ``` 示例文件测试后已还原,`git diff` 为空。只改 `ouckey.sty` 一个文件。 ### 关于页数 3 页 → 4 页。抬头从 3 行变 9 行,这是「一行一项」的必然代价。 **你已确认接受。** 第 4 页只有说明文字末尾 2 行 + 签字行。 行距我收紧到了 15bp(正文是 16bp)—— 抬头是查阅信息,不需要正文行距, 9 行省了约 52bp,相当于 3 行正文的空间。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/ouc_latex_template#22