tabularx 和 multicolumn:列宽不正确

tabularx 和 multicolumn:列宽不正确

我用 制作了下表,tabularx并期望第二行中的所有单元格都具有相同的宽度,因为它们都使用了multicolumn{2}。但事实并非如此。相反,第三和第六个单元格的宽度是其他单元格宽度的两倍。

第 3 行至第 6 行存在类似的问题。每行上的第一个和第四个单元格只有其应有宽度的一半(考虑到它使用了)multicolumn{4},而其他单元格的宽度则是预期宽度的两倍。

我是不是做错了什么,或者tabularx它的行为和我想的不一样?我以为X列的宽度与用 定义的列数有关\multicolumn{n}。例如,如果整个表格有 12 列,我指定\multicolumn{2}列宽为整个表格的六分之一。但显然情况并非如此,或者说它只适用于第一行……

\documentclass{article}
\usepackage{tabularx}
\usepackage{booktabs}

\begin{document}

\begin{table}[h]
    \begin{tabularx}{\textwidth}{*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & \multicolumn{6}{|X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols}\\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & &  \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
    \end{tabularx}
\end{table}

\end{document}

答案1

你问,

难道我做错了什么?

简短回答:是的。

稍微长一点的答案:您的tabularx环境包含太多相互冲突的信息;结果就是一团糟,无法产生“正确”的列宽。在某些情况下,事情看起来似乎很顺利,这完全是运气好。然而,这只是巧合。结果呢?您需要停止提供这些相互冲突的指令。

让我们把整体分解tabularx成更小的部分。让我们从一个看起来很简单的案例开始:

\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

这看上去没什么问题,不是吗?但是,一如既往,外表是会骗人的。潜伏在表面之下的麻烦的根源是滥用符号:列类型X被迫承担双重职责。首先,由于应该有 12 个等宽列,因此每列的默认可用宽度等于\textwidth/12-2\tabcolsep-(13/12)\arrayrulewidth。(旁注:$13/12 \approx 1.08333$。)但在 中\multicolumn{6}{X|}{6 cols},单元格的宽度实际上是大 6 倍。[我会让软件包的设计者tabularx解释为什么这种符号滥用被允许滑动并且不会引发错误...]幸运的是——我必须强调,这纯属巧合——结果还不错,即 LaTeX 能够正确计算出组合列的宽度。这是因为

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

可以简化为

\begin{tabularx}{\textwidth}{| X | X |}
        \hline
        1 col & 1 col \\
        \hline
\end{tabularx}

不再存在符号滥用的问题。换句话说,LaTeX 通过丢弃第一个tabularx环境中内置的冗余来解决这个难题。


让我们考虑一个稍微有趣的案例:

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} \\
        \hline
\end{tabularx}

观察一下,符号的滥用导致X-type 列的宽度可能有三个 [3!] 个不同的值。但片刻的思考表明,这必须与

\begin{tabularx}{\textwidth}{|*{6}{X|}}
        \hline
        \multicolumn{3}{|X|}{3 cols} & 
        \multicolumn{3}{ X|}{3 cols} \\
        \hline
        1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
        \hline
\end{tabularx}

再次重申,这不会产生歧义。关键在于,实际上没有 12 个独立列,只有 6 个,而 LaTeX 现在拥有足够的信息来在 类型列宽度的两个可能值之间来回切换X。换句话说,更简单的问题没有致命的歧义。


最后,让我们讨论一下无法明确消除冗余的情况。

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols (?!)} & a & b & 
        \multicolumn{4}{ X|}{4 cols (?!)} & c & d  \\
        \hline
\end{tabularx}

在此处输入图片描述

LaTeX 已获得足够的信息来推断出第 2 行前三个单元格的总宽度必须等于第 1 行第一个单元格的宽度。但是,剩下的信息不足以让 LaTeX 推断出第 2 行第一个单元格的宽度必须等于4次该行中单元格 2 和 3 的宽度。但结果却是第 2 行中三个单元格的宽度相等。哎哟。

为了解决这个问题,真正需要的是这样的:

\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

其结果如下:

在此处输入图片描述

其之所以“如预期般工作”,是因为我们现在已经给了 LaTeX 足够的信息,让它推断出 给出的单元格宽度\multicolumn{4}{|X|}{4 cols}必须是 给定单元格宽度的三分之二(而不是三分之一)\multicolumn{6}{|X|}{6 cols}

tabularx这个故事的寓意是什么?如果你没有提供足够有用的信息,那么它将无法正确解决列宽分配问题,请不要感到惊讶。


为了完整起见,这里列出了tabularx上面提到的所有六种环境:

在此处输入图片描述

\documentclass{article}
\usepackage{tabularx,calc}

% code needed for the final 'tabularx' example:
\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}

\setlength\parindent{0pt} % just for this example

\begin{document}

\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{|X|X|}
        \hline
        1 col & 1 col \\
        \hline
\end{tabularx}


\bigskip
\begin{tabularx}{\textwidth}{*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{|*{6}{X|}}
        \hline
        \multicolumn{3}{|X|}{3 cols} & 
        \multicolumn{3}{ X|}{3 cols} \\
        \hline
        1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
        \hline
\end{tabularx}

\bigskip
\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols (?!)} & a & b & 
        \multicolumn{4}{ X|}{4 cols (?!)} & c & d  \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

\end{document}

答案2

Xp宽度由整个表格决定,

因此,如果前两列是|X|X||您的示例中缺少第一列),那么
\multicolumn{2}{|X|}{...} 将跨越列,但...将被强制进入由其确定的宽度的 parbox,该X宽度小于所需宽度的一半。

您可以使用\multicolumn{2}{|l|}{...},因此宽度是自动的,或者如果您需要换行,
\multicolumn{2}{|>{\hsize=\dimexpr2\hsize+2\tabcolsep+\arrayrulewidth}X|}{...}
那么p列就是两列的宽度X和跨越的填充和规则。

答案3

我决定自己回答这个问题,因为我无法使用提供的答案修复表格。无论如何,感谢@mico 和@david-carlisle。

总结:我放弃向 LaTeX 解释如何确定正确的列宽,而是手动完成。以下代码生成了我想要的表格:

\begin{tabular}{*{12}{l}}
        \hline
        \multicolumn{6}{|p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
            6 col
        } & \multicolumn{6}{p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
            6col
        } \\
        \hline
        \multicolumn{2}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } \\
        \hline
        \multicolumn{4}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
            4 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col 
        }& 
        \multicolumn{4}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
            4 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-7\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col 
        } \\
        \hline      
    \end{tabular}

长版本:我尝试使用@Mico 的示例修复我的表格,但失败了。例如以下代码:

\documentclass{article}
\usepackage{tabularx,calc}
\begin{document}

\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

\end{document}

在本地和https://www.papeeria.com。我没有意识到 papeeria.com 上的默认 LaTeX 版本太旧了(2015 年的!)无法正确编译该代码。在本地,使用新文档时代码可以正确呈现,但将其粘贴到现有文档中时则不行。我没有调试这个,因为当我意识到这一点时,我已经有了自己的解决方案。

更新:我找到了一个更优雅(并且更短)的解决方案,使用tabularray

\documentclass{article}
\usepackage{tabularray}
\begin{document}
\begin{table}
\begin{tblr}{
        width=\textwidth,
        colspec={|X|X|X|X|X|X|X|X|X|X|X|X|},
        hline{1-Z} = {1-Z}{solid},
        vline{1-Z} = {1-Z}{solid},
        cells = {l},
        cell{1}{1,7} = {c=6}{l},
        cell{2}{1,3,5,7,9,11} = {c=2}{l},
        cell{3-6}{1,7} = {c=4}{l},
        }
        6 cols & & & & & & 6 cols & & & & & \\
        2 cols & & 2 cols & & 2 cols & & 2 cols & & 2 cols & & 2cols & \\
        4 cols & & & & 1 col & 1 col & 4 cols & & & & 1col & 1col \\
\end{tblr}
\end{table}
\end{document}

这也得到了我想要的表格。

相关内容