第一个解决方案

第一个解决方案

我正在尝试将一个值存储在由另一个宏的参数构造的宏中,但是由于未创建宏,我肯定遗漏了一些东西。

梅威瑟:

\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
}

相关内容