复制表行 n 次

复制表行 n 次

我想复制表中的行,比如说,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}

相关内容