使用 etoolbox 列表填充表格

使用 etoolbox 列表填充表格

我正在尝试tabular用 etoolbox 列表填充环境:

\documentclass{article}

\usepackage{etoolbox}

\listadd\mylist{Ana}%
\listadd\mylist{Bob}%
\listadd\mylist{Cole}%

\newcommand*{\pco}{%
    \renewcommand*{\do}[1]{Person: & ##1 \\}
    \dolistloop{\mylist}
}

\begin{document}
    \begin{tabular}{r | l}
        \pco
    \end{tabular}
\end{document}

我的意思是生成如下表格:

Person: | Ana
Person: | Bob
Person: | Cole

相反,我得到的是:

Person: | Ana
BobCole |

我很难弄清楚这一点。我的第一个想法是,该\do命令被表理解为单个标记(即{Person: & ##1 \\})。但在第一个实例中情况并非如此:列表中的第一个项目成功分成两列。但是,以下项目并非如此;事实上,\do似乎完全被忽略了,并且每个列表项的值只是被打印出来。

我错过了什么?

答案1

改用\forlistloop

\documentclass{article}

\usepackage{etoolbox}

\newcommand{\pcodo}[1]{Person: & #1 \\}

\listadd\mylist{Ana}
\listadd\mylist{Bob}
\listadd\mylist{Cole}

\newcommand*{\pco}{\forlistloop{\pcodo}{\mylist}}

\begin{document}

\begin{tabular}{r | l}
\pco
\end{tabular}

\end{document}

不过,还有更好的方法。这里有一个与 类似的实现\xintFor,但允许逐步构建列表。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

% initialize a list
\NewDocumentCommand{\newlist}{m}
 { % #1=list name
  \seq_new:c { g_wasabi_list_#1_seq }
 }

% populate a list one item at a time
\NewDocumentCommand{\addtolist}{mm}
 {
  \seq_gput_right:cn { g_wasabi_list_#1_seq } { #2 }
 }

% use a list; "pre" and "post" are code executed before and after the loop
\NewDocumentCommand{\uselist}{mO{}mO{}}
 { % #1=list name, #2=pre, #3=template, #4=post
  \cs_gset:Nn \__wasabi_list_temp:n { #3 }
  #2
  \seq_map_function:cN { g_wasabi_list_#1_seq } \__wasabi_list_temp:n
  #4
 }

\ExplSyntaxOff

\newlist{my}

%% these commands can go anywhere, provided they are before
%% using the list
\addtolist{my}{Ana}
\addtolist{my}{Bob}
\addtolist{my}{Cole}

\begin{document}

\uselist{my}
  [\begin{tabular}{r|l}]
  {Person & #1 \\}
  [\end{tabular}]

\bigskip

\uselist{my}{#1, }

\end{document}

列表有多种使用方式,并具有不同的模板。

在此处输入图片描述

答案2

使用tabulars,通常更容易建立(即连续连接)一个标记列表,然后在过程结束时将其转储到输入流中。

\documentclass{article}

\usepackage{etoolbox}

\listadd\mylist{Ana}%
\listadd\mylist{Bob}%
\listadd\mylist{Cole}%

\newtoks\tabtoks
\newcommand*{\pco}{%
    \tabtoks{}%
    \newcommand*{\ZaZa}[1]{\tabtoks\expandafter{\the\tabtoks Person: & ##1 \\}}%
    \forlistloop\ZaZa{\mylist}%
    \the\tabtoks%
}

\begin{document}
    \begin{tabular}{r | l}
        \pco
    \end{tabular}
\end{document}

在此处输入图片描述

但是,感谢 jfbu 指出,这个问题可以更简单地解决。OP 代码的问题在于,&列分隔符在 下创建了不同的范围\halign,因此必须在该约束下工作,以使其他tabular单元格全局可用。例如,在 OP 的原始代码中,只需更改\renewcommand*{\do}[1]{Person: & ##1 \\}\gdef\do##1{Person: & ##1 \\} 即可使代码产生正确的输出。但是,感谢 egreg 指出\do全局重新定义是不可接受的,并指出\forlistloop是最佳替代方案。

日本保卫工会联合会提出以下决议:

\newcommand*{\pco}{%
  \gdef\ZaZa##1{Person: & ##1 \\}%
  \forlistloop\ZaZa{\mylist}%
}

产生可以工作的代碼。

\documentclass{article}

\usepackage{etoolbox}

\listadd\mylist{Ana}%
\listadd\mylist{Bob}%
\listadd\mylist{Cole}%

\newcommand*{\pco}{%
  \gdef\ZaZa##1{Person: & ##1 \\}%
  \forlistloop\ZaZa{\mylist}%
}

\begin{document}
    \begin{tabular}{r | l}
        \pco
    \end{tabular}
\end{document}

答案3

除了其他两个优秀的答案之外,我还可以提出这个不需要定义额外宏的答案:

\documentclass{article}

\usepackage{xinttools}

\newcommand\mylist{Ana, Bob, Cole}

\begin{document}
    \begin{tabular}{r | l}
        \xintFor #1 in \mylist \do{Person: & #1 \\}
    \end{tabular}

% or \xintFor #1 in {Ana, Bob, Cole}
% or \xintFor* #1 in {{Ana}{Bob}{Cole}}
\end{document}

相关内容