我可以使用pgffor
循环宏(控制序列)吗?例如\foreach \macro in {\lions,\tigers,\bears}
如果你还没搞清楚,我喜欢模块化!
假设我有三个命令需要修补:
\a1
\a2
\a3
伪代码
此代码是为了实现我想要的功能而尝试的。为了好玩并测试我的理解,我曾经\csname
创建名称中包含数字的宏。
\documentclass{article}
\usepackage{tikz}
\usepackage{regexpatch}
\expandafter\newcommand\csname a1\endcsname[1]{}
\expandafter\newcommand\csname a2\endcsname[1]{}
\expandafter\newcommand\csname a3\endcsname[1]{}
\foreach \macro in {\csname a1\endcsname,\csname a2\endcsname,\csname a3\endcsname} {%
\expandafter\xapptocmd{\macro}{\unexpanded{#1}, oh my!}{}{}% Apply patches to all macros in list
}%
\begin{document}
\csname a1\endcsname{Lions}
\csname a2\endcsname{tigers}
\csname a3\endcsname{and bears}
\end{document}
预期页面输出
Lions, oh my!
tigers, oh my!
and bears, on my!
替代半工作示例,无\csname
\documentclass{article}
\usepackage{tikz}
\usepackage{regexpatch}
\newcommand\lions[1]{}
\newcommand\tigers[1]{}
\newcommand\bears[1]{}
%\foreach \macro in {\lions,\tigers,\bears} {% Loop up the following junk
\xapptocmd{\lions}{\unexpanded{#1}, oh my!}{}{}% inefficient use of my time
\xapptocmd{\tigers}{\unexpanded{#1}, oh my!}{}{}% inefficient use of my time
\xapptocmd{\bears}{\unexpanded{#1}, oh my!}{}{}% inefficient use of my time
%}%
\begin{document}
\lions{Lions}
\tigers{tigers}
\bears{and bears}
\end{document}
输出
答案1
除了使用expl3
循环(如\clist_map_inline:nn
)之外,您还可以使用提供的etoolbox
。
\documentclass{scrartcl}
\usepackage{etoolbox,regexpatch}
\csdef{a1}#1{}
\csdef{a2}#1{}
\csdef{a3}#1{}
\begin{document}
\renewcommand*\do[1]{\expandafter\xapptocmd\csname#1\endcsname{##1, oh my!}{}{\typeout{Misreable filure}}}
\docsvlist{a1,a2,a3}
\csuse{a1}{Lions}\par
\csuse{a2}{tigers}\par
\csuse{a3}{and bears}
\end{document}
我使用了\csdef
和\csuse
只是为了向他们展示,您可以像往常一样使用\expandafter\newcommand\csname .. \endcsname
和\csname .. \endcsname
。
正如 egreg 所说,总是重复出现的问题\foreach
是一切都在组内。我从来没有想过,但我不知道为什么不定义类似的东西\foreach \foo in { a, b } { <code> }
,\let\save\foo \def\foo{a} <code> \def\foo{b} <code> \let\foo\save
这样可以解决很多问题。无论如何,如果你想为自己定义一个完整的宏来自动化你可以做的一切,例如,这两个选项:
\usepackage{etoolbox}
\newcommand\doforeach[2]{\renewcommand\do[1]{#2}\docsvlist{#1}}
或者
\usepackage{expl3}
\ExplSyntaxOn
\NewDocumentCommand \doforeach { +m +m } { \clist_map_inline:nn { #1 } { #2 } }
\ExplSyntaxOff
然后你就可以轻松使用
\doforeach{a1,a2,a3}{\expandafter\xapptocmd\csname#1\endcsname{##1, oh my!}{}{\typeout{Misreable filure}}}
而且您不需要输入困难的东西。
答案2
常见的问题:\foreach
在组中完成其工作,因此一旦组结束,补丁就会失效。但是,您正在尝试修补\macro
,这会扩展到\csname a1\endcsname
等等,因此尝试显然会失败。
定义\temp
为与“双重扩展”相同\macro
;修补它;全局重新定义该\csname
宏为修补版本。
\documentclass{article}
\usepackage{tikz}
\usepackage{regexpatch}
\expandafter\newcommand\csname a1\endcsname[1]{#1}
\expandafter\newcommand\csname a2\endcsname[1]{#1}
\expandafter\newcommand\csname a3\endcsname[1]{#1}
\foreach \macro in {\csname a1\endcsname,\csname a2\endcsname,\csname a3\endcsname}
{%
\expandafter\expandafter\expandafter\let\expandafter\expandafter\expandafter\temp\macro
\xapptocmd\temp{, oh my!}{}{}%
\global\expandafter\expandafter\expandafter\let\macro\temp
}
\begin{document}
\csname a1\endcsname{Lions}
\csname a2\endcsname{tigers}
\csname a3\endcsname{and bears}
\end{document}
如果您希望在补丁中使用参数说明符,可以这样做。请注意, 的倍数#
,因为我们在 的参数中\foreach
。
\documentclass{article}
\usepackage{tikz}
\usepackage{regexpatch}
\expandafter\newcommand\csname a1\endcsname[1]{}
\expandafter\newcommand\csname a2\endcsname[1]{}
\expandafter\newcommand\csname a3\endcsname[1]{}
\foreach \macro in {\csname a1\endcsname,\csname a2\endcsname,\csname a3\endcsname}
{%
\expandafter\expandafter\expandafter\let\expandafter\expandafter\expandafter\temp\macro
\xapptocmd\temp{##1, oh my!}{}{}%
\global\expandafter\expandafter\expandafter\let\macro\temp
}
\begin{document}
\csname a1\endcsname{Lions}
\csname a2\endcsname{tigers}
\csname a3\endcsname{and bears}
\end{document}
答案3
我宁愿使用\seq
列表并在里面扩展它。
\documentclass{article}
\usepackage{tikz}
\usepackage{regexpatch}
\expandafter\newcommand\csname macro1\endcsname[1]{}
\expandafter\newcommand\csname macro2\endcsname[1]{}
\expandafter\newcommand\csname macro3\endcsname[1]{}
\begin{document}
Before patching:
\csname macro1\endcsname{Lions}
\csname macro2\endcsname{Tigers}
\csname macro3\endcsname{and Bears}
\ExplSyntaxOn
\seq_set_from_clist:Nn \l_tmpa_seq {macro1,macro2,macro3}
\seq_map_inline:Nn \l_tmpa_seq {%
\exp_after:wN \xapptocmd\cs:w #1\cs_end:{##1,~oh~my!}{\typeout{Success!}}{}
}
\ExplSyntaxOff
After patching:
\csname macro1\endcsname{Lions}
\csname macro2\endcsname{Tigers}
\csname macro3\endcsname{and Bears}
\end{document}
其他版本,使用正确的参数##1
和以及带有的旁路\global\csletcs
,因为\foreach
仅运行它的代码组。
\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{regexpatch}
\expandafter\newcommand\csname a1\endcsname[1]{}
\expandafter\newcommand\csname a2\endcsname[1]{}
\expandafter\newcommand\csname a3\endcsname[1]{}
\begin{document}
\foreach \macro in {a1,a2,a3} {%
\let\santaslittlehelper\macro
\expandafter\xapptocmd\csname \santaslittlehelper\endcsname{##1, oh my!}{}{\typeout{Miserable failure}}% Apply patches to all macros in list
\global\csletcs{\macro}{\santaslittlehelper}
}
\csname a1\endcsname{Lions}
\csname a2\endcsname{tigers}
\csname a3\endcsname{and bears}
\end{document}