在 pdfLaTeX 中创建类似迭代器的宏(在函数编程意义上)的最简单方法是什么?
我想预定义一个元素列表(为了简化,我们可以假设它是纯字符串,例如 [C1, C2, C3] 或 [ad36bf, dea63f, 78f091]),并创建一个可以迭代此列表的宏,即每次使用它都会从列表中获取新元素。如果迭代器尝试访问列表中的更多元素,则应该出错,或者应该返回空内容。
例如,我希望
\deflist{A,B,C,D} % it doesn't need to use comma as separator
% ...
\el something \el xx \el
生产
A 某物 B xx C
我想使用这个宏来自动命名/编号用 TikZ/PGF 创建的图表中的节点......
答案1
这很简单expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\deflist}{O{,}m}
{
\seq_set_split:Nnn \l_narebski_list_seq { #1 } { #2 }
}
\NewDocumentCommand{\el}{}
{
\seq_item:Nn \l_narebski_list_seq { 1 }
\seq_pop_left:NN \l_narebski_list_seq \l_narebski_waste_tl
}
\seq_new:N \l_narebski_list_seq
\tl_new:N \l_narebski_waste_tl
\ExplSyntaxOff
\begin{document}
\deflist{A,B,C,D}
\el{} something \el{} xx \el{}
\deflist[-]{A-B}
\el{} something \el{} xx \el{}
\end{document}
输入被分成一个序列(分隔符周围的空格(可以作为 的可选参数进行更改\deflist
)被修剪掉);每次调用时,\el
都会传递第一个项目,然后将其从序列中弹出。
可以轻松添加对序列是否为空的检查:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\deflist}{O{,}m}
{
\seq_set_split:Nnn \l_narebski_list_seq { #1 } { #2 }
}
\NewDocumentCommand{\el}{}
{
\seq_pop_left:NN \l_narebski_list_seq \l_narebski_next_tl
% if the sequence is empty, the token list will contain \q_no_value
\quark_if_no_value:VTF \l_narebski_next_tl
{ $\langle$empty$\rangle$ }
{ \tl_use:N \l_narebski_next_tl }
}
\seq_new:N \l_narebski_list_seq
\tl_new:N \l_narebski_next_tl
\cs_generate_variant:Nn \quark_if_no_value:nTF { V }
\ExplSyntaxOff
\begin{document}
\deflist{A,B,C,D}
\el{} something \el{} xx \el{}
\deflist[-]{A-B}
\el{} something \el{} xx \el{}
\end{document}
除了打印之外<empty>
,还可以修改“真实”部分以发出警告或错误。
答案2
在这种情况下,项目之间用空格分隔,而不是用逗号分隔。如果您想要一个包含空格的项目,请将整个短语括在括号中,例如\deflist{A {B is the one} C D}
。
新的调用\deflist
将重置计数器并重新构建列表。
\documentclass{article}
\usepackage{readarray}
\newcommand\deflist[1]{\setcounter{itcount}{0}\getargsC{#1}}
\newcounter{itcount}
\newcommand\el{\stepcounter{itcount}\ifnum\value{itcount}>\narg\else%
\csname arg\romannumeral\value{itcount}\endcsname\ \fi}
\begin{document}
\deflist{A B C D} % it doesn't need to use comma as separator
% ...
\el something \el xx \el
\deflist{A {B is the one} C D}
\el something \el xx \el
\deflist{A B} % it doesn't need to use comma as separator
\el something \el xx \el
\end{document}