我想复制表中的行,比如说,n
时间,但不幸的是,下面的示例无法编译。据我了解,该\foreach
命令应该复制其参数中的内容,但这里没有这样做。我查看了编译器中的错误消息,我知道是什么原因造成的。我认为这是表环境的构造方式。我现在正在考虑将命令封装为一个组,但我不知道如何做到这一点。实现此结果的最佳方法是什么?一些解释将不胜感激。
\documentclass[letterpaper]{article}
\usepackage{amsmath,amssymb,lipsum}
\usepackage{tikz,calc}
\newcommand{\test}[1]{%
\foreach \i in {1,...,#1}
{%
t1 & t2 \\%
}}
\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}
答案1
主要问题是\foreach
团体工作,但不仅仅如此。
最简单的做法是先在宏中构建表,然后扩展它:
\documentclass{article}
\usepackage{tikz}
\newcommand{\test}[1]{%
\def\temp{}%
\foreach \i in {1,...,#1}
{%
\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}%
}%
\temp}
\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}
该\temp
宏被初始化为空,然后在每次循环时被扩充;最后被展开。这\gdef
是必要的,因为循环周围有隐式组。
\test{3}
发生的事情本质上
\def\temp{}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
\temp
当 TeX 仍在寻找第一行第一个单元格中的材料时,一切都会发生。第一行指出\temp
扩展为零;然后执行第二行:每个都\expandafter
扩展其后的第二个标记;对于前两个,它是另一个,\expandafter
所以我们得到\temp
。因此,第二行相当于说
{\gdef\temp{t1 & t2 \\}}
但在第三行执行相同操作时,效果是
{\gdef\temp{t1 & t2 \\t1 & t2 \\}}
第四行变成
{\gdef\temp{t1 & t2 \\t1 & t2 \\t1 & t2 \\}}
\foreach
补充括号表示围绕循环的隐式组。因此\gdef
是必要的,因为否则的重新定义\temp
将在组末尾消失。
标记的存在&
不是问题,因为 TeX 会在括号之间扫描它,因此它们不会用于标记单元格的结尾。这个问题有时会困扰某些人。
最后\temp
会产生代币
t1 & t2 \\t1 & t2 \\t1 & t2 \\
TeX 将能够正确查看并构建表格。
一个不太可读但功能完全相同的定义是
\makeatletter
\newcommand{\test}[1]{%
\let\@temp\@empty
\foreach \i in {1,...,#1}
{%
\g@addto@macro\@temp{t1 & t2 \\}%
}%
\@temp}
\makeatother
强制性的 LaTeX3 版本:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\repeatrow}{mm}
{
\azet_repeat_row:nn { #1 } { #2 }
}
\tl_new:N \l_azet_rows_tl
\cs_new_protected:Npn \azet_repeat_row:nn #1 #2
{
\tl_clear:N \l_azet_rows_tl
\prg_replicate:nn { #1 } { \tl_put_right:Nn \l_azet_rows_tl { #2 \\ } }
\tl_use:N \l_azet_rows_tl
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{cc}
\repeatrow{3}{t1 & t2}
\end{tabular}
\end{document}
其工作原理与“经典”解决方案非常相似,但它使用的是\prg_replicate:nn
而不是\foreach
。命令是
\prg_replicate:nn { <integer expression> } { <code> }
并评估<integer expression>
(因此也可能调用\repeatrow{3*5}{...}
);然后它<code>
在第二个参数中重复第一个参数中指定的次数。
此命令前面是 的类似物\def\temp{}
:标记列表变量\l_azet_rows_tl
被清除并且<code>
只是“将第二个参数附加到 ” \azet_repeat_row:nn
(反过来是 的“内部”版本\repeatrow
)。然后,标记列表变量的内容被传递以供使用(类似于第一个解决方案中的说法\temp
)。
答案2
您实际上不需要 for-each 宏,您只需要注意循环计数器和表格单元格中的组正确交互。
下面生成三行表,没有任何大(或小)的包开销。
\documentclass{article}
\newcommand{\test}[1]{%
t1 & t2 \\
\ifnum#1>1
\expandafter\test\expandafter{\numexpr#1-1\expandafter\relax\expandafter}\fi
}
\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}
答案3
这是使用 Latex 3 的替代方案,
\documentclass[letterpaper]{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \Copy \prg_replicate:nn
\ExplSyntaxOff
\begin{document}
\begin{tabular}{cc}
\Copy{4}{t1 & t2 \\}
\end{tabular}
\end{document}