Tikz/PGF 有一个非常有用的 \foreach 实现,它允许构造
\foreach \x / \y in {1/a,2/b,3/c,4/d} {\x is a lot like \y}
您可以在其中迭代一对列表。此命令仅在 tikz 环境中有效,因此在序言中尤其无效,我想使用它来定义大量看起来非常相似的宏,例如\newcommand{\task\x}{\function\y}
;(实际上我在 tikz 中定义新形状,每个形状都有五十行或更多代码,因此重复几百次确实不切实际)。
tex 中是否有可以轻松执行类似操作的函数?我知道我可以使用 ForArray 函数或嵌套 for 循环来组合此功能,但结果似乎比较不雅致,我希望这里有人可能有一个干净的方法(或使用数组或循环的干净实现)。
答案1
您可以在序言中将\xdef
(全局扩展定义)与\csname ... \endcsname
inside一起使用\foreach
。它在序言中起作用,但将内容包含在需要全局定义的组中。循环“变量”(宏)必须在定义之前/期间扩展,否则宏将只包含\y
而不是其当前内容。
这里有一个如何定义宏的例子,比如\mymacroa
、\mymacrob
等等,它将包含一个\dostuff
获取\y
内容的调用。
\documentclass{article}
\usepackage{pgffor}
\foreach \x/\y in {a/1,b/2,c/3,d/4} {
\expandafter\xdef\csname mymacro\x\endcsname{%
\noexpand\dostuff{\y}%
}%
}
\newcommand{\dostuff}[1]{\texttt{(#1)}}
\begin{document}
\mymacroa
\mymacrob
\mymacroc
\mymacrod
\end{document}
如果您想做一些不同的事情,比如定义 PGF 形状,那么最好只是累积所需的宏调用并扩展循环变量,然后执行累加器。
以下代码将添加\dostuff{<x>}{<y>}
到\mycommands
在任何组外循环后执行的。然后它包含\dostuff {a}{1}\dostuff {b}{2}\dostuff {c}{3}\dostuff {d}{4}
。
\documentclass{article}
\usepackage{pgf}
\usepackage{pgffor}
\usepackage{etoolbox}
\newcommand{\mycommands}{}
\newcommand{\dostuff}[2]{%
\pgfdeclareshape{#1}{%
\anchor{#2}{...}%
}%
}
\foreach \x/\y in {a/1,b/2,c/3,d/4} {%
\xappto{\mycommands}{\noexpand\dostuff{\x}{\y}}%
}
%\show\mycommands
\mycommands
\begin{document}
\end{document}
答案2
pgffor
确实可以在外部环境中工作tikzpicture
,尽管对于某些应用程序来说它不够强大。
一个问题是,你错误地使用了\newcommand
。你不能改用\newcommand{\task\x}{\function\y}
、使用\@namedef{task\x}{\function\y}
或类似的东西。
另一个问题是由于pgffor
。它是以组为单位执行的,使用它定义新宏时必须扩展变量。
\x
示例解决方案,您必须小心控制和的扩展\y
:
\documentclass{article}
\usepackage{pgffor}
\foreach \x/\y in {a/1,b/2,c/3} {
\expandafter\xdef\csname cmd\x\endcsname{number \y}
}
\begin{document}
\cmda, \cmdb, \cmdc
\end{document}
另一种解决方案是使用etoolbox
,这是首选:
\documentclass{article}
\usepackage{etoolbox}
\def\dodo#1/#2{\csdef{cmd#1}{number #2}}
\def\do#1{\dodo#1}
\docsvlist{a/1,b/2,c/3}
\begin{document}
\cmda, \cmdb, \cmdc
% we obtain: number 1, number 2, number 3
\end{document}
答案3
使用 catoptions 包,辅助功能就不再必要,您还可以使用任意列表分隔符。此外,在生效\dodo
之前,列表的每个元素都会先去掉多余的前导空格和尾随空格。\do
\documentclass{article}
\usepackage{catoptions}[2011/10/22]
\begin{document}
\def\do#1/#2{\csndef*{cmd#1}{number #2}}
\dofunclist{a/1, b/2, c/3}
%\dofunclist[;]{a/1; b/2; c/3}
\cmda, \cmdb, \cmdc
\end{document}