在 \multicolumn column-specification 中使用宏参数

在 \multicolumn column-specification 中使用宏参数

创建表格标题时,通常使用 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@@

相关内容