使用 pgfkeys 作为宏的参数

使用 pgfkeys 作为宏的参数

我想在宏中使用 pgfkeys,但发现文档有点难以上手。以下代码应该可以说明我试图解决的问题:

\documentclass{article}

\usepackage{pgfkeys}

\newcommand{\mymacro}[2][]{
  Before the elements.
  % if the elements key is set and the list is not empty
  % extract the members and list them separated by commas...
  % else print `No elements passed.'
  #2
}

\begin{document}

\mymacro[elements={a, b, c}]{Foo.}

% The above should expand to:
%
% Before the elements. a, b, c. Foo.

\mymacro{Foo.}

% The above should expand to:
%
% Before the elements. No elements passed. Foo.

\end{document}

答案1

编辑:这是根据评论修改后的答案。我采纳了 Andrew Stacey 提出的许多建议。

PGF 关键功能种类繁多、功能强大,因此需要花费大量精力才能弄清楚如何使用它们来做您想做的事情!让我先分部分介绍我的解决方案,然后再完整介绍。

\newcommand{\mymacro}[2][elements/.initial = {No elements passed.}]{
  Before the elements.
  % if the elements key is set and the list is not empty
  % extract the members and list them separated by commas...
  % else print `No elements passed.'
  {\pgfkeys{/mymacro/.cd, #1, print}}
  #2
}

您应该这样定义\mymacro。您必须调用\pgfkeys可选参数,以便实际处理要使用的键。请注意,有必要在所有 PGF 键的路径树中为您的键提供一个“目录”,并且自己创建目录似乎是个好主意,我称之为/mymacro(像 UNIX 目录)。

工作原理是,它将elements处理给定的值,然后print输出结果,如果未指定任何元素,则输出错误消息。我通过让默认参数\mymacro直接设置值来处理这个问题elements,而无需进行任何处理。

我还小心地将对的调用\pgfkeys放在一个组中,因为的操作elements不会初始化其值,并且后续的调用\mymacro可能会相互干扰。

\pgfkeys{/mymacro/.cd,
 print/.code = {\pgfkeysvalueof{/mymacro/elements}},
 elements/.code = {%
  \pgfkeys{/mymacro/.cd,
           list/.list = {#1},
           elements/.add={\{}{\}}
  }%
 },
 list/.code = {\pgfkeys{/mymacro/elements/.append = (#1)}}
}

现在我们必须定义这些键的操作。在我看来,你的elements钥匙是一个储物箱,里面的东西都会被打印出来print。然而,它elements = {a, b, ...}使用.code我为其定义的子键(“处理程序”),处理它在被调用为 时收到的值。这个东西会调用list键的.list处理程序(pgffor如果您只是pgfkeys单独加载而不是通过 加载,则需要该包tikz),它只会循环遍历给定的任何逗号分隔列表,并应用于list/.code每个项目。作为一个不具创意的例子,我只是在项目周围加上括号。之后,您还可以对elements/.code结果进行后处理,例如通过前置和后置括号。

这种让键既可以作为值的存储,又可以作为作用于该值的代码的技巧非常有用。至少它允许你编写语义上有吸引力的语句,而elements = {a,b,c}不必担心这是否真的分配,因为它既可以是代码,也可以是处理结果的后续分配。

也许可以更巧妙地设置,以便使用更少的键,但这在本例中会造成混淆。以下是完整的 LaTeX 文件:

\documentclass{article}

\usepackage{pgfkeys,pgffor}

\newcommand{\mymacro}[2][elements/.initial = {No elements passed.}]{
  Before the elements.
  % if the elements key is set and the list is not empty
  % extract the members and list them separated by commas...
  % else print `No elements passed.'
  {\pgfkeys{/mymacro/.cd, #1, print}}
  #2
}

\pgfkeys{/mymacro/.cd,
 print/.code = {\pgfkeysvalueof{/mymacro/elements}},
 elements/.code = {%
  \pgfkeys{/mymacro/.cd,
           list/.list = {#1},
           elements/.add={\{}{\}}
  }%
 },
 list/.code = {\pgfkeys{/mymacro/elements/.append = (#1)}}
}

\begin{document}
\mymacro[elements = {a,b,c}]{Foo}

\mymacro{Bar}

\mymacro[elements = {1,2,3}]{Baz}

\mymacro{Quh}
\end{document}

答案2

解决方案取决于你想用元素做什么,但有一个想法是

\documentclass{article}

\usepackage{pgfkeys}
\def\mymacroempty{}

\pgfkeys{/mymacro/.cd,
elements/.code = \def\myelements{#1}}

\newcommand{\mymacro}[2][]{%
\pgfkeys{/mymacro/.cd,elements={}}
\pgfqkeys{/mymacro}{#1}   
\ifx\myelements\mymacroempty 
   No elements passed.
\else 
\myelements.
\fi
  #2
}

\begin{document}

\mymacro[elements={a, b, c}]{Foo.}

\mymacro{Foo.}

\end{document}

在此处输入图片描述

相关内容