我正在尝试将一个值存储在由另一个宏的参数构造的宏中,但是由于未创建宏,我肯定遗漏了一些东西。
梅威瑟:
\documentclass{article}
\RequirePackage{pgfkeys}
\newcommand\zkeys[1]{\pgfkeys{/prefix/.cd,#1}}
\newcommand\zsetup[2]{
\zkeys{
#1/.store in=\z#2,
}
}
\zsetup{keya}{storagea}
\zsetup{keyb}{storageb}
\zkeys{
keya=test,
}
\begin{document}
\zstoragea % Undefined control sequence.
\end{document}
答案1
新的解决方案
另一种更灵活的方法是扩展处理程序\pgfkeys
接受,使用新的处理程序.store in cs
,它的功能与基本相同.store in
,但不以完整的控制序列名称作为值,而是以字符列表作为值,最终的控制序列由此构建。因此,以下调用将相等:
foo/.store in=\mymacro
foo/.store in cs=mymacro
完整示例如下
\documentclass{article}
\RequirePackage{pgfkeys}
\newcommand\zkeys[1]{\pgfkeys{/prefix/.cd,#1}}
\pgfkeys{/handlers/.store in cs/.code=\pgfkeysalso{%
\pgfkeyscurrentpath/.code=\expandafter\def\csname#1\endcsname{##1}}%
}
\newcommand\zsetup[2]{%
\zkeys{
#1/.store in cs=z#2,
}%
}
\zsetup{keya}{storagea}
\zsetup{keyb}{storageb}
\zkeys{
keya=test,
}
\begin{document}
\zstoragea % Undefined control sequence.
\end{document}
旧解决方案
当您输入 时\z#2
,TeX 会将其解析为命令名称\z
,后跟从第二个参数插入的标记。如果您想从一系列字符/标记构建新的控制序列,则必须使用序列\csname ...\endcsname
,其中在本例中...
为z#2
。
然而,在这种特定情况下store in=\csname z#2\endcsname
不会起作用,因为\csname
调用必须扩展一次才能从字符构建实际的新控制序列,但不能超过一次,否则构建的宏将尝试扩展自身。
一个可能的解决方案是将整个键定义包装到中\edef
,在其中的所有命令前加上前缀\noexpand
,并在每个地方使用\unexpanded\expandafter{...}
,我们只需要一个扩展步骤:
\newcommand\zsetup[2]{
\edef\temp{%
\noexpand\zkeys{
#1/.store in=\unexpanded\expandafter{\csname z#2\endcsname},
}%
}\temp
}
\zstoragea
将会扩展为test
。
答案2
这里有两个解决方案。它们都注意在将 的第一个参数\zsetup
传递给 之前不要扩展它\zkeys
,也不会在当前组内定义或覆盖任何宏作为副作用。
第一个解决方案
\documentclass{article}
\usepackage{pgfkeys}
\newcommand{\zkeys}[1]{\pgfkeys{/prefix/.cd,#1}}
\newcommand*{\zsetup}[2]{%
\begingroup
\edef\arg{\unexpanded{#1/.store in=}%
\expandafter\noexpand\csname z#2\endcsname}%
\expandafter
\endgroup
\expandafter\zkeys\expandafter{\arg}%
}
\zsetup{keya}{storagea}
\zsetup{keyb}{storageb}
\zkeys{
keya=test,
}
\begin{document}
\zstoragea % Print 'test'
\end{document}
第二种解决方案
代码相同,但定义不同\zsetup
:
\newcommand*{\zsetup}[2]{%
\begingroup
\def\tmp##1{\zkeys{#1/.store in=##1}}%
\expandafter\expandafter\expandafter
\endgroup
\expandafter\tmp\csname z#2\endcsname
}