> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/zh-cn/shen-ru-wen-zhang/14-how-do-tex-engines-typeset-tables.md).

# TeX 引擎如何排版表格

## TeX 引擎如何排版表格

## 引言：本系列涵盖什么内容？

制作美观的表格可能是一项耗时的工作——无论你使用的是可视化排版工具、LaTeX，还是像 HTML 或 markdown 这样的标记语言。对于 LaTeX 用户来说，表格排版尤其常被列为许多人的“痛点”之一，这也许可以从“tables”成为 tex.stackexchange 上最 [高频标记主题之一看出来](https://tex.stackexchange.com/tags).

除了 tex.stackexchange 上的答案和示例之外，哪怕是对 LaTeX 表格排版相关支持资料做一次粗略浏览，也能发现许多与表格相关的信息资源：

* Overleaf 的 [帮助页面](https://www.overleaf.com/learn/latex/tables) 以及其他网站，例如 [learnlatex.org](https://www.learnlatex.org/en/lesson-08)
* CTAN（Comprehensive TeX Network，TeX 综合网络）列出了超过 [70 个 TeX/LaTeX 宏包](https://ctan.org/topic/table) 与创建表格有关
* 整本 [使用 LaTeX 进行表格排版的书](https://www.amazon.co.uk/Typesetting-Tables-LaTeX-Herbert-Voss/dp/1906860254)
* 一个很优秀的 [在线 LaTeX 表格生成器](https://www.tablesgenerator.com/latex_tables)

简单搜索一下 [LaTeX tables](https://www.google.com/search?q=latex+tables) 会得到海量结果，列出许多提供帮助、建议、示例和解释的网站。

### TeX，而不是 LaTeX

既然已经有如此丰富的关于使用 LaTeX 进行表格排版的文献，还值得再写些什么吗——更多表格示例，以及对宏包命令的枚举/演示？有没有一种方式来探讨表格排版这一主题，能够提炼出或聚焦于表格排版的基本原理和概念？是有的，但这需要剥开 LaTeX 的洋葱……

我们决定撰写一个文章系列，旨在为读者提供有关其底层 *机制* 的背景信息和解释，即基于 TeX 的表格排版。与其聚焦于使用特定的 LaTeX 宏/宏包来排版表格，我们将探讨 TeX 引擎的 *底层行为* ：研究那些为 LaTeX 宏命令奠定基础的低层排版机制。最终目标是提炼并解释基于 TeX 的表格排版的核心方法和算法——希望能帮助读者/用户更好地理解表格为何会那样运作。剥去 LaTeX 宏这层保护壳后，不可避免的结果就是会接触到那些凌乱的低层细节；而用户通常（且心安理得地）是通过层层 LaTeX 宏代码与这些细节隔绝开的。

为研究、撰写并配图这些文章花费了大量时间，因此我们希望它们能成为对现有文献的一个有价值的补充，为读者提供有助于理解这一 TeX 排版复杂领域的材料。我们需要强调的是，本系列文章将 *不* 涉及讨论 *美学* 上的表格设计——这是一个充满主观偏好的话题，其争论必须在别处展开……

### 探索 TeX 表格的机制：你该怎么做？

为了探索并撰写 TeX 引擎内部发生的更底层机制和过程，例如表格排版，Overleaf 使用 Martin Ruckert 的 [Web2W 过程](https://w3-o.cs.hm.edu/users/ruckert/public_html/web2w/index.html).

构建（编译）了 Knuth 的 TeX 引擎的“调试”版本。传统上，构建 TeX 使用的是一个称为 Web2C 的过程，它在 TeX Live 中使用，通过将 TeX 的原始 Pascal 源代码转换为其 C 等价物来生成 C 代码。该过程生成的 C 代码从来都不是给人读的，只是给 C 编译器读的。机械生成的 C 代码 *极其* 难以阅读或修改以用于实验。

相比之下，Web2W 生成的 C 源代码（可在 [这里](https://w3-o.cs.hm.edu/users/ruckert/public_html/web2w/ctex.c)） *在可读性上* 远远高于 Web2C 生成的代码。因此，Web2W 的 C 源代码更适合为学习/实验目的进行修改。

Web2W 生成了一个 TeX 版本（“CTeX”），它 *极其* 非常接近 Knuth 的原始程序：“CTeX”不包括 Web2C 过程引入的许多更改和增强——例如 SyncTeX、命令行处理以及通过 Kpathsea 进行文件搜索。尽管你要放弃这些有价值的增强功能，生成的（Web2W）C 代码却相对容易借助 Knuth 发表的 TeX 源代码来查阅，即便 TeX 是用 Pascal 编写的。

* **关于名称的说明：** 严格来说，“TeX”这个名称只能指 Donald Knuth 最初编写并发布的软件。对其软件作出的任何修改，都必须对所得的基于 TeX 的排版软件使用不同的名称。这里，我们使用 Web2W 过程构建了一个引擎，而它在本质上仍然是 Knuth 的原始软件。不过，为避免歧义，我们将使用“CTeX”来表示使用 Web2W 构建的特定版本；同时我们也会使用“TeX”来表示 Knuth 原始引擎，或表示基于 Knuth 的 TeX 原理的排版语言的一般术语。我们希望读者能原谅我们在严格使用正确术语方面偶尔的疏漏：我们希望语境能够传达其含义/意图。

CTeX 的调试版本是在 [Eclipse IDE](https://www.eclipse.org/downloads/packages/)中运行的，这使得可以实时观察实现 Knuth 为支持表格排版而设计的低层原始（内置）TeX 命令及算法的 C 代码处理过程。

下面这段简短的视频（约 90 秒）演示了 CTeX 引擎在 [Eclipse IDE](https://www.eclipse.org/downloads/packages/):

{% embed url="<https://videos.ctfassets.net/nrgyaltdicpt/7drdFwYR6h5xD88XnurDIH/36511f504755ab274f4da2e3f3fc1ce5/TeXtables.mp4>" %}

中运行。

### 为什么要用较旧的 TeX 引擎来研究表格？

首先，印刷版书籍 [TeX:The Program](https://www.amazon.co.uk/Computers-Typesetting-TeX-Program-TEX/dp/0201134373)——其中列出了并解释了 TeX 的源代码——即使在出版 30 多年后的今天（1986 年），仍然是理解 TeX 内部运作这片朦胧水域的一份极其便利的指南。当然，你也可以自己排版 TeX 源代码文档，例如参见 Overleaf 项目 [排版 TeX、e-TeX 或 pdfTeX 的源代码文档](https://www.overleaf.com/latex/examples/typeset-the-source-code-documentation-for-tex-e-tex-or-pdftex/qkgfgyspnhcv)。自 1986 年《TeX:The Program》出版以来，新的 TeX 引擎不断演进，包括 pdfTeX、XeTeX 和 LuaTeX，它们都引入了《TeX:The Program》中未记录的特性和命令，原因很简单：这些特性当时并不存在于 Knuth 的原始软件中。

对于许多核心过程，例如 TeX 的表格排版，《TeX:The Program》中记录的代码至今仍然可作为研究基础——尽管 TeX 源代码是用 Pascal 编写的。此外，Knuth 的 TeX 编译起来相对容易且快速——尤其得益于极其有用的 [Web2W](https://w3-o.cs.hm.edu/users/ruckert/public_html/web2w/index.html) 过程，该过程由 Martin Ruckert 开发。编译的容易/快速，使得对 TeX 进行简单修改变得更加方便——例如在本系列后文中会用到的 SVG 图形的创建。

### 理解 TeX 与 LaTeX 的区别

许多读者已经知道，LaTeX 实际上并不是一个 *可执行的* 排版程序，而是一大套命令（*宏*），这些命令最终是用一种更底层的排版/编程语言 TeX 编写的。你的 LaTeX 代码只有在经过一个名为 *TeX 引擎*的可执行程序处理后，才会产生排版输出——这个软件位于你的 LaTeX 代码（文档）与排版后的 PDF 之间。如今，用户可以选择不同的 TeX 引擎来排版他们的 LaTeX 代码，包括 pdfTeX、XeTeX 以及 LuaTeX 的各种变体。

刚接触 TeX/LaTeX 生态系统的人，常常也完全可以理解地，会被他们遇到的那些听起来很神秘的工具名称弄得晕头转向：TeX、LaTeX、pdfTeX、pdfLaTeX、XeTeX、XeLaTeX、LuaTeX 和 LuaLaTeX。如果你也有同感，Overleaf 的文章 [名称里有什么：TeX 各种风格指南](/latex/zh-cn/shen-ru-wen-zhang/55-what-s-in-a-name-a-guide-to-the-many-flavours-of-tex.md) 可以帮到你，其中解释了这些术语的来源和含义。

#### 方言与 TeX 原语

每个 TeX 引擎都有一组内置命令，称为 *原始命令* ，它们共同构成了该引擎所使用的 TeX 排版语言的“方言”，反映了各引擎内置的能力。这里，用于描述 TeX 引擎内置命令的“primitive（原语）”一词 *不* 并不意味着这些命令是基础的或简单的，而是说它们是基本且不可分割的：不是由其他命令构成的（与宏不同）。所有 TeX 引擎共享一大组核心原语，但有些引擎也包含该引擎特有的原语——从而产生了 TeX 的“方言”这一概念。

无论使用哪种 TeX 引擎来排版你的 LaTeX 文档，它的工作都是处理（“执行”）用于编写和构造文档的那组 LaTeX 命令（即宏）。实际上，TeX 引擎会将你的 LaTeX 代码（宏）“转换”回 *其组成的* TeX 引擎原语命令，之后由引擎执行这些命令来完成实际排版。你并不 *必须* 一定需要 *用 LaTeX 命令来通过 TeX 引擎排版文档——你* 可以 *完全用 TeX 原语来构造文档，也就是直接使用 TeX 引擎内置的底层* TeX 编程语言

。不过按今天的标准来看，TeX 语言相当古奥，通常被认为是一门难以编程的语言——为了实现排版目标，它还可能需要大量内置原语，这会使编程任务容易出错，而且可能显得重复。 *宏*为了避免必须直接用 TeX 语言编写，或不断重复输入同一串命令，TeX 引擎允许你创建称为 [宏包](https://wiki.contextgarden.net/Main_Page)的“快捷方式”。通过创建宏，你可以定义自己的命令，把可能很长且复杂的 TeX 语言原语序列（或其他宏）打包成一个单独的“更高层”命令。TeX 程序员可以编写非常复杂的宏，在一个命令中封装大量功能——例如 LaTeX 提供的那些命令。通过使用宏包，例如 LaTeX（或

## 一开始……

在为数学排版和复杂的断行设计算法的同时，Knuth 还面临着为他的 TeX 软件编写程序以排版表格这一挑战。显然，任何表格构造算法都不能过于受限，否则就会让需要自由创建几乎无限种表格布局的用户感到受挫。此外，表格单元可以包含各种内容，包括数学、图形以及被排成漂亮行的文本片段——事实上，任何 TeX 能够排版的内容都可以放入其中。要实现这种灵活性，就要求 TeX 的表格构建算法与 TeX 排版机制的其他部分协同工作。

然而，TeX 引擎为其表格构造能力所提供的灵活性付出了代价：内置（原语）表格排版命令在低层行为上存在诸多细节和微妙之处，这类命令共有 9 个：

* **`\halign`**, **`\valign`**：核心表格构造命令
* **`\tabskip`**：放置在 \halign 列之间或 \valign 行之间的胶水
* **`\cr`**：表格中所有行都必须使用的“回车”终止符
* **`\noalign`**：在 \halign 的行之间或 \valign 的列之间插入材料
* **`\everycr`**：在检测到 \cr 后读取的命令（记号寄存器）
* **`\span`**：一个双重用途的命令：\span 可创建跨列或跨行的单元格，或者展开表格导言中的命令（我们将详细讨论这一点）
* **`\omit`**：跳过某个特定单元格的模板
* **`\crcr`**：用于宏中，以避免用户忘记所需的 \cr 时出错

在我们探索表格构造的旅程中，会遇到这些命令。

### 对这些挑战的遥远回响

埋藏在 [TeX 的源代码](https://www.overleaf.com/latex/examples/typeset-the-source-code-documentation-for-tex-e-tex-or-pdftex/qkgfgyspnhcv) 中的是对实现用于排版表格的低层命令 \halign 和 \valign 的主题的一段有些令人望而生畏的介绍：

> “每当 \halign 和 \valign 能正常工作时，都算是一种奇迹，因为它们横跨了 TeX 的许多控制结构。因此，现在这一页或许并不是初学者开始阅读这个程序的最佳地方；最好先掌握其他所有内容。”

Knuth 接着说道

> “请注意，当 \halign 正在被处理时，我们会毫不犹豫地把控制权交给 TeX 的其余部分。在关键时刻，会调用一个对齐例程出来执行一点小动作，但大多数时候这些例程只是潜伏在背景中。这有点像后催眠暗示。”

从这些评论看来，可以合理地得出结论：即使对 Knuth 而言，实现 TeX 的表格排版也“算是一项挑战”——既要为用户提供控制和灵活性，又要同时确保 TeX 的自动表格构建算法与 TeX 的核心排版过程协调良好。

作者坦率地承认 TeX 表格排版能力背后的代码和算法十分复杂，但也对在相对少量、尽管密集的 Pascal（或 C）代码中所包含的巨大能力表达由衷钦佩。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/zh-cn/shen-ru-wen-zhang/14-how-do-tex-engines-typeset-tables.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
