我有一个命令需要超过 9 个参数。我偶然发现了这个解决方案:如何定义接受超过 9 个参数的命令。这在普通文本中运行良好。但我尝试在tabular
环境中使用它,但出现undefined control sequence
错误。这是一个 MWE:
\documentclass{article}
\begin{document}
\newcommand*\foo[9]{%
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\def\tempi{#9}%
\foocont
}
\newcommand\foocont[1]{\tempa & \tempb & \tempc & \tempd & \tempe & \tempf & \tempg & \temph & \tempi & #1 \cr}
\begin{tabular}{*{10}c}
\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{a}
\end{tabular}
\end{document}
如果删除所有&
、\cr
和tabular
环境,只\foo
使用 10 个参数调用,则代码可以很好地编译(打印出123456789a
)。
我怎样才能使这个“参数扩展”与之一起工作tabular
?
答案1
执行 的第一个表格单元格\foo
也是一个本地组。在下一个之后,、 、 ...&
的本地含义将丢失。\tempb
\tempc
有几种方法
全局定义
\documentclass{article}
\begin{document}
\newcommand*\foo[9]{%
\gdef\tempa{#1}%
\gdef\tempb{#2}%
\gdef\tempc{#3}%
\gdef\tempd{#4}%
\gdef\tempe{#5}%
\gdef\tempf{#6}%
\gdef\tempg{#7}%
\gdef\temph{#8}%
\gdef\tempi{#9}%
\foocont
}
\newcommand\foocont[1]{\tempa & \tempb & \tempc & \tempd & \tempe & \tempf &
\tempg & \temph & \tempi & #1 \cr}
\begin{tabular}{*{10}c}
\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{a}
\end{tabular}
\end{document}
扩张
以下示例\temp...
通过 扩展了宏。这通过和强大的命令\protected@edef
支持 LaTeX 保护机制。宏甚至可以仅在本地分配:\protect
\temp...
\documentclass{article}
\begin{document}
\newcommand*\foo[9]{%
\begingroup
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\def\tempi{#9}%
\foocont
}
\makeatletter
\newcommand*\foocont[1]{%
\protected@edef\process@me{%
\endgroup
\tempa & \tempb & \tempc & \tempd & \tempe & \tempf &
\tempg & \temph & \tempi & #1 \cr
}%
\process@me
}
\makeatother
\begin{tabular}{*{10}c}
\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{a}
\end{tabular}
\end{document}
一级扩展
\protect
如果宏仅展开一次,则可以避免 使用脆弱命令。e-TeX 的\temp...
命令\unexpanded
会有所帮助。不使用 e-TeX 的替代方案是使用令牌寄存器。
\documentclass{article}
\begin{document}
\newcommand*\foo[9]{%
\begingroup
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\def\tempi{#9}%
\foocont
}
\newcommand*\foocont[1]{%
\edef\processme{%
\endgroup
\unexpanded\expandafter{\tempa} &
\unexpanded\expandafter{\tempb} &
\unexpanded\expandafter{\tempc} &
\unexpanded\expandafter{\tempd} &
\unexpanded\expandafter{\tempe} &
\unexpanded\expandafter{\tempf} &
\unexpanded\expandafter{\tempg} &
\unexpanded\expandafter{\temph} &
\unexpanded\expandafter{\tempi} & #1 \cr
}%
\processme
}
\begin{tabular}{*{10}c}
\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{a}
\end{tabular}
\end{document}
答案2
正如 David 在评论中所建议的,另一种方法是使用逗号分隔的语法:
\foo{1,2,3,4,5,6,7,8,9,a}
然后,您可以循环遍历条目并将它们放到位。由于我们在表格内工作,因此仍然存在一些扩展问题,但您可以使用电子工具箱\foreach
使用以下方法循环遍历参数来构建每一行前列腺素。
这样做的主要优点是代码可以轻松扩展到任意数量的参数。其次,代码更短,更容易维护,因为您不需要像 Heiko 那样对每个参数进行特殊处理。如果您真的想要,您可以检查参数数量是否正确,但在我看来这似乎有点过头了,因为输出中清除的行太少,而太多会自动给出错误。
我改变了 MWE,以说服自己这样做是可行的:
以下是代码:
\documentclass{article}
\usepackage{pgffor}
\usepackage{etoolbox}
\newcommand\foo[1]{%
\global\def\sep{}% will expand to & except for the first column
\global\let\myrow\relax% will become the row built from #1
\foreach \arg in {#1} {% loop over #1 to build \myrow
\xappto\myrow{\sep\arg}% global expansion
\gdef\sep{&}% make the next separator &
}%
\myrow\\% print the row
}
\begin{document}
\begin{tabular}{*{10}{c|}}
\foo{1,2,3,4,5,6,7,8,9,a}
\foo{111,22,,444,55,{10,000},77,88,99,a}
\end{tabular}
\end{document}
(顺便说一句,正如booktabs 包,使用垂直线来分隔列通常不是一个好主意。我上面这样做只是为了表明代码可以正常工作。)