创建表格标题时,通常使用 1 个单元格\multicolumn
。为了简化此操作,可以创建一个表格标题宏:
% this definition works, but doesn't allow controlling alignment
\newcommand{\Th}[1]{\multicolumn{1}{l}{\textbf{#1}}}
但是,我们可能并不总是想要左对齐的列;有时右对齐或居中等可能更合适。但是,添加控制列规范的可选参数非常困难:
\newcommand{\Th}[2][l]{\multicolumn{1}{#1}{\textbf{#2}}}
% when used: ! Misplaced \omit.
% \multispan ->\omit
% \@multispan
% l.8 \Th{Header}
% & \Th[r]{header (\textsc{usd})} & \Th{header} \\
以下是我对可能的解决方案的一些想法;它们产生的错误消息位于定义之上。我在这里遗漏了什么?
这是对“在表格中重复使用列规范”的回答这意味着解决方案#3(临时创建一个新的列类型并使用它)应该可以工作,但它仍然会产生错误。
我也知道makecell
包裹通过其宏提供了部分解决方案\thead
,但其可配置性不够精细——而且我想知道为什么这些定义无论如何都不起作用。
\documentclass{article}
\usepackage{array}
\makeatletter
% attempt #1: edef/expandafter solution
% when used: ! Use of \\Th doesn't match its definition.
% \text@command #1->\def \reserved@a {
% #1}\ifx \reserved@a \@empty \let \check@...
% l.16 \Th{Header}
% & \Th{header (\textsc{usd})} & \Th{header} \\
\newcommand{\Th}[2][l]{%
\edef\@multicolumncontents{{1}{#1}{\textbf{#2}}}%
\expandafter\multicolumn\@multicolumncontents}
% attempt #2: expandafter/begingroup solution
% when used: ! Misplaced \omit.
% \multispan ->\omit
% \@multispan
% l.21 \Th{Header}
% & \Th[r]{header (\textsc{usd})} & \Th{header} \\
\newcommand{\Th}[2][l]{%
\expandafter\multicolumn\begingroup{1}{#1}{\textbf{#2}}\endgroup}
% attempt #3: newcolumntype solution
% when used: ! Misplaced \omit.
% \multispan ->\omit
% \@multispan
% l.31 \Th{Header}
% & \Th[r]{header (\textsc{usd})} & \Th{header} \\
\newcommand{\Th}[2][l]{%
\newcolumntype\@thcol{#1}%
\multicolumn{1}{\@thcol}{\textbf{#2}}}
\makeatother
\begin{document}
\begin{tabular}{rrr}
\Th{Header} & \Th[r]{header (\textsc{usd})} & \Th{header} \\
data & 12831 & data \\
1238 & 12.38 & 4893258439 \\
$\delta$ & 10 & 1238 \\
\end{tabular}
\end{document}
答案1
这是因为它\multicolumn
必须是行之后&
或行开头的“第一件事”。
没有不可扩展的指令可以干预,并且用定义的命令\newcommand
具有可选参数\@ifnextchar
用于确定是否[
跟随,这最终需要不可扩展的\futurelet
,比插入替换文本要早得多。
有一个非常简单的解决方案:使用xparse
可以定义带有可选参数的可扩展命令,并提供强制性的命令。
\documentclass{article}
\usepackage{xparse}
\NewExpandableDocumentCommand{\Th}{O{l}m}{\multicolumn{1}{#1}{\textbf{#2}}}
\begin{document}
\begin{tabular}{rrr}
\Th{Header} & \Th[r]{header (\textit{usd})} & \Th{header} \\
data & 12831 & data \\
1238 & 12.38 & 4893258439 \\
$\delta$ & 10 & 1238 \\
\end{tabular}
\end{document}
答案2
当您在表格中使用 时\multicolumn
,实现会通过结合两个 TeX 基元\omit
(删除单元格的列格式)和\span
(将两个列单元格“合并”为一个)来实现所需的效果。但是,有一个限制:如果\omit
出现在单元格中,它必须是第一个不可展开的标记。
在\Th
没有可选参数的版本中,这没问题,因为这里只涉及完全可扩展的命令,最终导致\omit
实际上是第一个不可扩展的标记。另一方面,带有可选参数的版本在内部使用不可扩展的定义和赋值,因此会\omit
在标记流的稍后某个地方出现,因此会出现错误Misplaced \omit
。
因此,诀窍是以某种方式重写,使其完全可扩展到发挥作用\Th
的程度:\multicolumn
\documentclass{article}
\usepackage{array}
\makeatletter
\def\Th#1#{%
\if\relax\detokenize{#1}\relax
\expandafter\Th@@\expandafter l%
\else
\Th@#1%
\fi
}
\def\Th@[#1]\fi{\fi\Th@@{#1}}
\def\Th@@#1#2{\multicolumn{1}{#1}{\textbf{#2}}}
\makeatother
\begin{document}
\begin{tabular}{rrr}
\Th{Left} & \Th[c]{\textit{Center}} & \Th[r]{Right} \\
xxxxxxxxxxxxxx & xxxxxxxxxxxxxx & xxxxxxxxxxxxxx \\
xxxx & xxxx & xxxx \\
xxxxxxx & xxxxxxx & xxxxxxx \\
\end{tabular}
\end{document}
\Th
读取直到第一个标记的任何内容,并检查和{
之间的部分是否为空。如果是,则使用默认对齐参数调用。否则,我们解析可选参数 via并使用传递的对齐参数调用。\Th
{
\Th@@
l
\Th@
\Th@@