tabular 的第一个引数,即 {lcr} 这样的 列指定,不只是罗列对齐方式的地方。它其实是一门小语言:除了列数和对齐,还能在这里指定让 LaTeX 在每个单元格前后插入声明、替换列间空白,或 成组重复列。其中许多功能不属于普通 tabular,而是由 array 包 添加。本页从基本的 l、c、r、p{width} 出发,依次说明 m{width} 与 b{width}、>{…} 与 <{…}、@{…} 与 !{…},以及 *{n}{…}。
列指定这门小语言
四个基本类型已在另一页介绍。l、c、r 分别左对齐、居中、右对齐,并按内容的 自然宽度 扩展,不会换行。只有 p{width} 会被排成指定宽度的段落盒,内容超出时会 换行。按照 array 包的内部说法,p{width} 等价于 \parbox[t]{width},也就是 顶部对齐 的段落。这个默认的“顶部”正是接下来两个同类列的对照点。
从这里开始介绍的大多数记号,如 m/b、>/<、@/!、*,都需要在导言区写入 \usepackage{array} 后才能使用。array 随 TeX Live 和 MiKTeX 标准安装,很多表格包(tabularx、booktabs 等)也会在内部载入它,所以它常常已经生效。即便如此,显式载入仍然最稳妥。
段落列的垂直位置 — p、m、b
会换行的段落列有三种,差别只在 单元格的垂直位置,也就是盒子在行内如何垂直对齐。按照 array 手册的定义,p{width} 是 \parbox[t],即 顶部对齐;m{width} 把内容 垂直居中到该行;b{width} 是 \parbox[b],即 底部对齐。m 和 b 是 array 包添加的,普通 tabular 没有。
它在同一行同时包含高单元格(换成多行的 p 列或大图片)和单行单元格时特别有用。默认 p(顶部)会让相邻的短单元格贴在行顶,视线与高单元格中部对不上。使用 m{width} 时,该列内容会位于行的上下中央,从而与旁边的单行单元格自然对齐。含图片的单元格,或左边标签、右边长说明的表格,都很适合用它。
\usepackage{array}
% ...
\begin{tabular}{ p{3cm} m{3cm} b{3cm} }
\hline
上端揃え (p) & 縦中央 (m) & 下端揃え (b) \\
この列は parbox[t]。 & この列は行の上下中央に。 & この列は parbox[b]。 \\
\hline
\end{tabular}即使宽度和正文完全相同,p、m、b 也会改变各单元格的上下位置。还要注意,在这三种段落列内部,\parindent(段落缩进)默认是 0(需要时可用 >{\setlength{\parindent}{1em}} 等方式加回来)。
| 指定符 | 垂直位置 | 等价 parbox | 提供者 |
|---|---|---|---|
p{wd} | 顶部 | \parbox[t]{wd} | 标准 |
m{wd} | 中部 | 在行内垂直居中 | array |
b{wd} | 底部 | \parbox[b]{wd} | array |
在单元格前后插入 — >{…} 与 <{…}
array 包的核心功能是 >{decl} 和 <{decl}。>{decl} 会在该列 每个单元格内容之前 立即插入 decl;<{decl} 则在内容 之后 插入。比如写 >{\bfseries}l,该左对齐列的所有单元格都会变成 粗体,不必在每个单元格中单独写 \bfseries。>{\itshape}c 得到居中斜体,>{\color{red}}r 得到右对齐红色,依此类推。
>{…} 中也可以放 对齐声明。段落列(p、m、b)默认两端对齐,但 >{\raggedright}p{4cm} 会生成 左齐(右边不齐) 的列,>{\centering} 生成居中列,>{\raggedleft} 生成右齐段落列。这就能满足“要换行,但不想两端对齐”的细微需求。
不过这里有一个 严重陷阱。\raggedright、\raggedleft、\centering 三个命令会在内部 重新定义行结束符 \\。如果使用这些声明的 >{…} 列位于表格 最后一列,\\ 就不再作为“行结束”工作,可能导致错误或输出错乱。解决方法是在声明 最后 加上 array 提供的 \arraybackslash:写 >{\raggedright\arraybackslash}p{4cm} 就能恢复 \\ 的行结束功能。\centering 和 \raggedleft 也同样需要。
另一个常用技巧是让 整列进入数学模式。写 >{$}c<{$} 会在每个单元格前后分别插入 $,于是该列所有单元格都会作为 行内数学 排版;数字或符号很多的列就不用每格都写 $…$。反过来,在本身已经处于数学模式的 array 环境中使用 >{$}…<{$},两个 $ 会相互抵消,使 只有该列进入文本模式。
需要注意的是,>{…} 和 <{…} 中应写 声明(declaration)。像 >{\bfseries}、>{\itshape} 这样后面不再取引数的形式没有问题,但 不能以需要引数的命令结尾。例如 >{\textbf} 会试图把后续单元格内容当作它的引数读取,从而出错(想加粗应使用声明形式 \bfseries)。array 手册也提醒,>{\textbf} “既不会让整列变粗,也不会让第一个字符变粗”。
调整列边界 — @{…} 与 !{…}
LaTeX 默认会在两列之间插入 \tabcolsep 的空白(默认每侧 6pt,两侧合计为两倍)。把 @{decl} 放在列指定的那个位置,会 移除那里的列间空白,并改为插入 decl(用 array 手册的话说,就是“抑制 inter-column space,并插入 decl.”)。
主要有两种用途。第一是 裁掉表格外侧留白:在列指定两端放 @{}(空声明),会移除第一列左侧和最后一列右侧的 \tabcolsep,使表格与正文左边距齐平;这是 booktabs 表格中常见的写法。第二是 插入分隔字符:若要按小数点对齐数字,可把数字分成整数部分列和小数部分列,并在中间放 @{.},这样小数点就会固定位置对齐,得到 小数点对齐。
与 @{…} 相对应的是 !{decl}。它可以写在竖线 | 的位置,并用任意 decl 代替竖线。它与 @{…} 的决定性区别是:!{…} 不会移除普通列间空白。因此它适合“想在列之间画虚线,但保留列间内边距”的情况,例如把 arydshln 包的虚线命令放进 !{…}。
顺带一提,载入 array 后,竖线 | 的行为也会稍有变化:列间距会按线条粗细 变宽(在标准 LaTeX 中,线条位于已有空白内,列间距不会增加)。不过专业表格中通常应避免竖线本身,这个话题留到“线条与出版级表格”页面讨论。
重复列 — *{n}{…}
当许多相同指定的列连续出现时,可以用 *{count}{spec} 折叠重复。按照 array 手册的定义,它等价于“spec 的 count 份拷贝”。例如六个居中列可以写 *{6}{c},而不是 cccccc。重复单元也可以包含多个指定:*{3}{|c}| 会展开为 |c|c|c|。当要重复包含 >{…} 或 @{…} 的长指定时尤其有用,例如 *{4}{>{$}c<{$}} 一次生成四个居中的数学模式列。
组合多个机制的示例
最后,下面这个例子把前面工具塞进一个列指定中。第 1 列是粗体标签列(>{\bfseries}l);第 2 列是左齐且会换行的段落列(>{\raggedright\arraybackslash}p{5cm},这里它不是最后一列,所以并非严格必需,但习惯上仍加 \arraybackslash);第 3、4 列用 *{2}{…} 一起生成居中的数学模式列;两端的 @{} 则裁掉外侧留白。
\usepackage{array}
% ...
\begin{tabular}{@{} >{\bfseries}l >{\raggedright\arraybackslash}p{5cm} *{2}{c} @{}}
\hline
記号 & 意味 & 値 & 単位 \\
\hline
$c$ & 真空中の光速。物理定数のひとつ。 & $2.998\times10^{8}$ & m/s \\
$g$ & 標準重力加速度。地表付近での近似値。 & $9.807$ & m/s$^2$ \\
\hline
\end{tabular}结果是:符号列统一为粗体,含义列在 5cm 宽度内左齐换行,两列数值居中排列,整张表没有外侧留白并与正文左端齐平。列语言的强项就是能在一行中写入多个机制,但也容易变得难读。因此常用组合最好用 \newcolumntype{yourletter}{…} 命名为 自定义列类型,之后就能像 {C C C} 这样简洁复用(这是 array 包的功能)。
顺带一提,用来按小数点对齐数字时,现代且可靠的选择是 siunitx 包的 S 列,而不是这里提到的 @{.}。S 列会解析每个数字,并正确对齐整数部分、小数点、小数部分、指数,甚至不确定度,同时整理分组和有效数字格式。请与“宽表与自动宽度”页面一起参照。