我正在为初学者准备一些带有表格的练习,而无需借助额外的软件包。
我在一个多列表格中发现了这个异常,最简单的情况是
\documentclass{article}
\begin{document}
\section{Wrong}
\begin{tabular}{|c|*{12}{c|}}
\hline
x2 col & \multicolumn{2}{c|}{1x2a} & \multicolumn{2}{c|}{1x2b} & \multicolumn{2}{c|}{1x2c} & \multicolumn{2}{c|}{1x2d} & \multicolumn{2}{c|}{1x2e} & \multicolumn{2}{c|}{1x2f}\\ \hline
x3 col & \multicolumn{3}{c|}{1x3a} & \multicolumn{3}{c|}{1x3b} & \multicolumn{3}{c|}{1x3c} & \multicolumn{3}{c|}{1x3d} \\ \hline
\end{tabular}%
\section{Right}
\begin{tabular}{|c|*{12}{c|}}
\hline
x2 col & \multicolumn{2}{c|}{1x2a} & \multicolumn{2}{c|}{1x2b} & \multicolumn{2}{c|}{1x2c} & \multicolumn{2}{c|}{1x2d} & \multicolumn{2}{c|}{1x2e} & \multicolumn{2}{c|}{1x2f}\\ \hline
x4 col & \multicolumn{4}{c|}{1x4a} & \multicolumn{4}{c|}{1x4b} & \multicolumn{4}{c|}{1x4c} \\ \hline
\end{tabular}
\end{document}
第一个表格中的多列单元格\multicolumn{3}{c|}{…}
不跨越三列;而在第二个类似的表格中,表格工作正常。
我在这个网站上找到了最近的参考资料(通过添加一个空行解决)但坦率地说,我不明白为什么会发生这种情况。
我正在寻找一种具有“预测”能力的解释来教导他人。一个人如何决定先验(编译之前)是否需要更正某个特定的表格?
答案1
您称之为“异常”的事情,其他人可能将其视为用户错误。
您为第一个表提供的结构(标记为“错误”)是不足的,这意味着您没有向 LaTeX 提供足够的信息来正确确定在 x3 行中设置列边界的位置。请查看下面的屏幕截图,并注意如果添加 x1 行,并且 12 个数据单元中的每一个都有虚拟内容,会发生什么:现在 LaTeX 确实有足够的信息来确定在 x3 行中绘制列边界的位置。
您标记为“正确”的第二个表恰好可以工作 - 但这只是运气好。与其定义 12 个数据列并
\multicolumn{2}{c|}{...}
在第 x2 行中提供 6 个指令,\multicolumn{4}{c|}{...}
在第 x4 行中提供 3 个指令,为什么不只定义 6 个数据列,去掉第 x2 行中的包装器,并将第 x4 行中\multicolumn{2}{c|}
的所有实例替换为?\multicolumn{4}{c|}
\multicolumn{2}{c|}
\documentclass{article}
\usepackage{array}
\newcommand\mc[2]{\multicolumn{#1}{c|}{#2}} % handy shortcut macro
\begin{document}
\section{Wrong}
\begin{tabular}{|c|*{12}{c|}}
\hline
x2 row & \mc{2}{1x2a} & \mc{2}{1x2b} & \mc{2}{1x2c} & \mc{2}{1x2d} & \mc{2}{1x2e} & \mc{2}{1x2f}\\
\hline
x3 row & \mc{3}{1x3a} & \mc{3}{1x3b} & \mc{3}{1x3c} & \mc{3}{1x3d} \\
\hline
\end{tabular}
\smallskip\noindent
\begin{tabular}{|c|*{12}{c|}}
\hline
x1 row & . & . & . & . & . & . & . & . & . & . & . & . \\
\hline
x2 row & \mc{2}{1x2a} & \mc{2}{1x2b} & \mc{2}{1x2c} & \mc{2}{1x2d} & \mc{2}{1x2e} & \mc{2}{1x2f}\\
\hline
x3 row & \mc{3}{1x3a} & \mc{3}{1x3b} & \mc{3}{1x3c} & \mc{3}{1x3d} \\
\hline
\end{tabular}
\section{Right (really?)}
\begin{tabular}{|c|*{12}{c|}}
\hline
x2 row & \mc{2}{1x2a} & \mc{2}{1x2b} & \mc{2}{1x2c} & \mc{2}{1x2d} & \mc{2}{1x2e} & \mc{2}{1x2f}\\
\hline
x4 row & \mc{4}{1x4a} & \mc{4}{1x4b} & \mc{4}{1x4c} \\
\hline
\end{tabular}
\smallskip\noindent
\begin{tabular}{|c|*{6}{c|}}
\hline
x1 row & 1x2a & 1x2b & 1x2c & 1x2d & 1x2e & 1x2f \\
\hline
x2 row & \mc{2}{1x4a} & \mc{2}{1x4b} & \mc{2}{1x4c} \\
\hline
\end{tabular}
\end{document}
附录回答 OP 的后续问题。为了更好地理解我上面关于 OP 的tabular
环境不确定的说法,请考虑 OP 的第一个环境的以下简化版本tabular
(我省略了标题列和数据列 7 至 12):
\documentclass{article}
\usepackage{array} % for 'w' column type
\begin{document}
\begin{tabular}{|*{6}{p{100in}|}}
\hline
\multicolumn{2}{|c|}{wwww} & \multicolumn{2}{c|}{bbbb} & \multicolumn{2}{c|}{cccc} \\
\hline
\multicolumn{3}{|c|}{dddd} & \multicolumn{3}{c|}{eeee}\\
\hline
\end{tabular}
\begin{tabular}{|*{60}{wc{50cm}|}}
\hline
\multicolumn{20}{|c|}{wwww} & \multicolumn{20}{c|}{bbbb} & \multicolumn{20}{c|}{cccc} \\
\hline
\multicolumn{30}{|c|}{iiii} & \multicolumn{30}{c|}{zzzz}\\
\hline
\end{tabular}
\end{document}
请注意,第一个
tabular
环境被定义为拥有 6 列,每列名义上是 100 英寸或大约 2.5 米宽 [!]。不用担心:环境tabular
是不是宽度超过 15 米。呼!发生了什么事?首先,请注意,没有一个单元格的宽度为一列。(从某种意义上说,这是一件好事,因为这样的单元格在构造上应该是 100 英寸宽……)
其次,请注意,上行单元格的宽度
c
(根据命令\multicolumn
)分别为字符串“wwww”、“bbbb”和“cccc”的自然宽度。而且,由于字母w
比b
或更宽c
,上行的第一个单元格明显比其他两个单元格宽。请注意,“底层”单列的宽度应为 100 英寸,但这一事实并不重要;LaTeX 能够利用的唯一信息是,在这三种情况下,组合单元格的列类型都是c
。现在转到第一个表的第二行,其中只有两个单元格;它们分别包含字符串“dddd”和“eeee”。同样,因为组合单元格的列类型是
c
,因此第一个单元格的宽度由字符串“dddd”的自然宽度给出。请注意,这是较少的大于上行第一个单元格的宽度。下行第二个单元格的宽度是表格环境整体宽度与下行第一个单元格的自然宽度之间的残差。
现在考虑第二种
tabular
环境。它被定义为有 60 [!] 列,每列宽度为 50 厘米,总可用宽度为 30 [!!] 米。(由于单元格边缘有空白填充,名义总宽度甚至大于名义可用宽度。)但是,同样,表格的整体结构尚未确定,因为没有信息将各个列链接到分组\multicolumn
结构。第二个表格第 1 行中的三个单元格名义上跨越 15、20 和 25 个“底层”列。但由于没有信息将分组单元格的外观与任何底层单列单元格联系起来,因此 LateX 所能做的就是采用
c
三个分组单元格的列类型,从而为单元格分配它们的“自然”宽度。而且,由于第二个表格第 1 行中的单元格内容与第一个表格第 1 行中的单元格内容相同,因此第二个表格的整体宽度与第一个表格的宽度完全相同。第二个表格名义上包含 60 列这一事实根本无关紧要。表格 2 下行的第一个单元格名义上包含 30 个底层列。但这也无关紧要,因为 LaTeX 没有信息来利用这个“事实”。事实上,即使第 2 行的第一个单元格包含两次与第 1 行第一个单元格一样多的底层行(30 对 15),其整体宽度较小,因为“iiii”比“wwww”占用的空间更小。
下行第二个单元格的宽度再次仅仅是一个残差。
我相信这些具体的例子已经能够让你相信原始表的结构确实是不确定的。
答案2
一个不太为人所知的事实是,当 TeX 处理带有\halign
,它有效合并跨越所有行的列。
例如,如果你这样做
\begin{tabular}{cc}
\multicolumn{2}{c}{abc}\\
\multicolumn{2}{c}{def}
\end{tabular}
(LaTeX 使用\halign
在后台使用),你会得到一个单列桌子。
让我们检查一下您的“错误”表格,实际上是显示相同问题的简化版本。我使用它\MC
来避免混乱。
\documentclass{article}
\newcommand{\MC}[2]{\multicolumn{#1}{c|}{#2}}
\begin{document}
\begin{tabular}{|c|*{6}{c|}}
\hline
x2 col & \MC{2}{1x2a} & \MC{2}{1x2b} & \MC{2}{1x2c} \\
\hline
x3 col & \MC{3}{1x3a} & \MC{3}{1x3b} \\
\hline
\end{tabular}
\end{document}
您可能以为第二行中的第二和第三个单元格会跨越第一行中的一个半单元格。抱歉,不是。
由于与 TeX 进行的列合并的交互,解释为什么会得到这样的输出有点复杂\multicolumn
。事实上,如果你添加一个“虚拟”行
\documentclass{article}
\newcommand{\MC}[2]{\multicolumn{#1}{c|}{#2}}
\begin{document}
\begin{tabular}{|c|*{6}{c|}}
\hline
x2 col & \MC{2}{1x2a} & \MC{2}{1x2b} & \MC{2}{1x2c} \\
\hline
x3 col & \MC{3}{1x3a} & \MC{3}{1x3b} \\
\hline
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}
\end{tabular}
\end{document}
你得到
嗯,也不是预期的输出。为什么?因为\tabcolsep
在所有情况下空格都相同,但第二行的空格较少。最后一列会补偿缺失或多余的空格。
\documentclass{article}
\newcommand{\MC}[2]{\multicolumn{#1}{c|}{#2}}
\begin{document}
\begin{tabular}{|c|*{6}{c|}}
\hline
x1 &
\MC{2}{1x2a} & \MC{2}{1x2b} & \MC{2}{1x2c} \\
\hline
x2 &
\MC{3}{\hspace*{1.33333\tabcolsep}1x3a\hspace*{1.33333\tabcolsep}} &
\MC{3}{1x3b} \\
\hline
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}&
\multicolumn{1}{c}{}
\end{tabular}
\end{document}
添加缺失的空格使得结果可能符合预期。
绝对不适合初学者。而且,这样的表格可以用其他工具获得,这也就意味着它们不够好。
答案3
带tabularray
包装
\documentclass[12pt,oneside]{book}
\usepackage{tabularx, }
\usepackage{tabularray}
\begin{document}
\begin{tblr}{
hlines={1.5pt},
vlines={1.5pt},
cell{1}{2,4,6,8,10,12} = {c=2}{c}, % multicolumn
cell{2}{2,6,10} = {c=4}{c}, % multicolumn
}
x2 col
& 1x2a
&
& 1x2b
&
& 1x2c
&
&1x2d
&
&1x2e
&
& 1x2f
&
\\
x4 col
&1x4a
&&&
&1x4b
&&&
& 1x4c
&&&
\\
\end{tblr}
\end{document}
答案4
视觉解释:(第一个是“适当填充的结果”,最后一个是你原来的“错误”结果)
您可以轻松看到为什么当填充趋向于 0 时,列会变得“合并”,无论 TeX 的内部实现是否将\halign
这些列一起处理。
为了便于理解,添加了淡红线。
\documentclass{article}
\usepackage{xcolor}
\begin{document}
% approach taken from https://tex.stackexchange.com/a/402428/250119 to ensure minimum row width, with modifications
\newcommand\specialpadding[1]{%
\omit % TeX primitive, read e.g. TeXbook for details...
\textcolor{red!20}{%
\smash{\rlap{%
\hspace*{-.2pt}% correct positioning for the faint red line, we start from halfway to the right of the rule and the default arrayrulewidth is 0.4pt
\rule[-25.2pt]{.4pt}{25.2pt}% the faint red line
}%
}}%
\hspace*{#1}% the padding itself
}
% miscellaneous note, the command above must not be protected/robust
\newcommand\testtable[1]{
\begin{tabular}{|c|*{12}{c|}}
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}&
\specialpadding{#1}
\\
\hline
x2 col & \multicolumn{2}{c|}{1x2a} & \multicolumn{2}{c|}{1x2b} & \multicolumn{2}{c|}{1x2c} & \multicolumn{2}{c|}{1x2d} & \multicolumn{2}{c|}{1x2e} & \multicolumn{2}{c|}{1x2f}\\ \hline
x3 col & \multicolumn{3}{c|}{1x3a} & \multicolumn{3}{c|}{1x3b} & \multicolumn{3}{c|}{1x3c} & \multicolumn{3}{c|}{1x3d} \\ \hline
\end{tabular}
\vspace{0.8cm}
}
\testtable{0.53cm}
\testtable{0.3cm}
\testtable{0.1cm}
\testtable{0cm}
\end{document}
如果您丢弃该\textcolor{red!20}{...}
部分,您将自动获得一个添加了一些“隐形”填充的解决方案。
另一种但更“易理解”的解决方案是指定明确的宽度。
(参见如何创建带有文本“raggedright/centered/raggedleft”的固定宽度表格列?如何在 p 型柱中居中)
\documentclass{article}
\begin{document}
\begin{tabular}{|c|*{12}{c|}}
\hline
x2 col & \multicolumn{2}{p{23.6pt}|}{1x2a} & \multicolumn{2}{p{23.6pt}|}{1x2b} & \multicolumn{2}{p{23.6pt}|}{1x2c} & \multicolumn{2}{p{23.6pt}|}{1x2d} & \multicolumn{2}{p{23.6pt}|}{1x2e} & \multicolumn{2}{p{23.6pt}|}{1x2f}\\ \hline
x3 col & \multicolumn{3}{p{41.6pt}|}{\centering 1x3a} & \multicolumn{3}{p{41.6pt}|}{\centering 1x3b} & \multicolumn{3}{p{41.6pt}|}{\centering 1x3c} & \multicolumn{3}{p{41.6pt}|}{\centering 1x3d} \\ \hline
\end{tabular}
\end{document}
请注意,如果我计算正确的话,2\tabcolsep+\arrayrulewidth
会添加到每个这样的列的宽度中,这就是为什么我分别指定宽度为 23.6pt 和 41.6pt - 实际宽度为 36pt 和 54pt。