pgfkeys 中的可选参数?

pgfkeys 中的可选参数?

我需要在 pgfkey 中添加可选参数吗?如下所示:

\pgfkeys{example/.code = (Argument: #2, optional argument: #1)}
\pgfkeys{example=[other]{some}}

应该导致

(Argument: some, optional argument: other)

\pgfkeys{example=[]{some}}

(Argument: some, optional argument: )

答案1

以下是我所知道的所有可以实现你想要的效果的方法:

  • 首先,你可以使用\pgfkeyslet一个通过 定义的宏\newcommand,它接受一个可选参数(Marc 的方法,稍微简化了一点,但功能性稍差)。缺点是:首先,你必须记住处理\pgfkeyseov插入的,而且,如果你只传递一个参数,括号会被删除,所以你必须把它们加倍。Marc 的方法没有这个问题(因此非常适合你的要求,但见我的最后一段),但要求你对分隔宏、内核函数和系统的内部工作原理进行相当深入的研究pgfkeys(手册甚至告诉您永远不需要.@cmd直接设置)。

  • 其次,您可以将.code处理程序直接与\newcommand宏一起使用。这样就无需处理\pgfkeyseov,但由于处理过程通过内部定义的宏进行,该宏采用由该控制序列分隔的单个参数,因此键的值会被处理两次所以你需要括号的级别。这显然是不可取的。

  • 第三,您可以使用.code 2 args(安德鲁的方法),如果您了解了双重处理并记得添加两级括号(第三级是不必要的,因为结果不会传递给需要括号的宏),那么这种方法就会有效。

  • 第四,您可以放弃使用一个键和两个参数的做法,而采用我认为正确的方法:定义两个键和一些强制强制/可选语义的默认值,并让所有内容通过宏进行设置,以便使用透明。在这个例子中,您只需编写\mykeyfour{mandatory = ?, optional = ?};如果您跳过mandatory,那么您不会让 TeX 崩溃,而只会得到一个(invalid)文本(尽管您可以让它引发错误,如果您愿意的话)。

我更喜欢第四种选择,因为在我看来,你所要求的实际上违反了键值范式。你似乎想要定义一个像 LaTeX 宏一样的键,但键的行为不像宏:它们的行为像键pgfkeys!它有自己的规则、自己的设置默认值和处理可选值的功能,以及相应的语法约定。我还想指出,只有在用户可能调用的顶级键中拥有可选参数才有意义:在任何内部键中,你都有足够的控制权来使所有参数明确。但是,在用户可见的键中,也有充分的理由不这样做。

不按你想要的方式做有很多技术原因,其中之一就是实际原因:它掩盖了代码的意图。有多个参数意味着必须从位置推断出参数的含义;但在键值系统中,整个观点是可以从键的名称推断出含义!如果你的键是/draw a box并且接受一个可选参数[height]和一个强制参数{width},那么你做得还不够好\makebox。如果我定义一个键值版本的 makebox,我会让它像这样工作\makebox[width = w, height = h]{text}(事实上,我在如何创建带有键值的命令?),这样您就知道随机数的含义。使用键意味着您可以自由地使用冗长的内容,分离函数的成分,并随时以任何顺序处理它们,并独立处理它们。利用这种自由!

以下是我的例子:

\documentclass{article}
\usepackage{pgfkeys}

\makeatletter
% arg 3 = \pgfeov
\newcommand\macro[3][]{(mandatory arg: #2; optional arg: #1)}
\pgfkeyslet{/key/.@cmd}{\macro}
\makeatother

\newcommand\macrotwo[2][]{(mandatory arg: #2; optional arg: #1)}
\pgfkeys{
 /key two/.code = \macrotwo#1
}

\pgfkeys{
 /key three/.code 2 args = {(mandatory arg: #1; optional arg: #2)}
}

\newcommand\mykeyfour[1]{%
 \pgfkeys{/key four,optional,mandatory,#1,print}%
}
\pgfkeys{
 /key four/.is family, /key four,
 optional/.default = {},
 optional/.store in = \keyfouroptional,
 mandatory/.default = {(invalid)},
 mandatory/.store in = \keyfourmandatory,
 print/.code = {(mandatory arg: \keyfourmandatory, optional arg: \keyfouroptional)},
}

\begin{document}
\noindent /key:

 \pgfkeys{/key = [optional]{mandatory}}

 % The braces are removed when the argument is scanned...
 \pgfkeys{/key = {{mandatory}}}

\noindent /key two:

 \pgfkeys{/key two = [optional]{mandatory}}

 % Would you believe that the braces are unwrapped TWICE?
 \pgfkeys{/key two = {{{mandatory}}}}

\noindent /key three:

 \pgfkeys{/key three = {mandatory}{optional}}

 % Braces removed twice again...
 \pgfkeys{/key three = {{mandatory}}}

\noindent /key four:

 \mykeyfour{mandatory = mandatory, optional = optional}

 \mykeyfour{optional = optional, mandatory = mandatory}

 \mykeyfour{mandatory = mandatory}

 \mykeyfour{optional = optional}
\end{document}

答案2

可以使用模式匹配技术来实现这一点,以处理多个参数。这在我的pgf手册的第 55.3.2 节(执行命令的键)中有解释。

\documentclass{minimal}
\usepackage{tikz}

\makeatletter
\def\mycommand{%
    \@ifnextchar[%
        \mycommand@%
        {\mycommand@[]}%
}
\def\mycommand@[#1]#2\pgfeov{%
    Argument=#2, Option=#1.%
}
\makeatother
\pgfkeyslet{/example/.@cmd}{\mycommand}

\begin{document}
\pgfkeys{/example=[other]{hello}}
\pgfkeys{/example=hello}
\end{document}

我还提供了以下解决方案,这是一个稍微好一点的 API,因为它只需要一个符号(在本例中为 +)来提供选项。

\documentclass{minimal}
\usepackage{tikz}

\makeatletter
\def\mycommand#1\pgfeov{%
    \mycommand@#1++\pgfeov%
}
\def\mycommand@#1+#2+#3\pgfeov{%
    Argument=#1, Option=#2.%
}
\pgfkeyslet{/example/.@cmd}{\mycommand}
\makeatother

\begin{document}
    \pgfkeys{/example=hello}
    \pgfkeys{/example=hello+world}
\end{document}

答案3

密钥处理者<key>/.code 2 args=<code>第二参数是可选的,如果未提供,将设置为空字符串。这在 PGF 手册(版本 2.10)第 492 页的第 55.4.3 节中。样式也一样(详见第 493 页的第 55.4.4 节)。

对于处理程序<key>/.code=<code>,参数也是可选的。但是,如果参数超过 2 个,则参数是必需的(即,对于<key>/.code n args={<argument count>}{<code>})。

答案4

由于我经常需要这样做,因此我创建了一些处理程序,用于以以下样式创建带有可选参数的键这个答案。如果使用此处理程序创建的键的值以 开头[,则预期匹配],并将封闭的标记视为可选参数。在定义中,#1表示可选参数和#2值的其余部分。

  • foo/.code with optarg with default value={<default>}{<def>}将使用可选参数的<def>默认值来定义创建键 foo 。<default>
  • foo/.code with optarg={<def>}使用空的默认值做同样的事情。
  • foo/.style with optarg with default value={<default>}{<def>}foo/.style with optarg={<def>}类似地创造风格。
\documentclass{article}

\usepackage{pgfkeys}

\makeatletter
  % Handlers for creating keys with optional arguments.
  \def\mypgf@install@code@with@optarg#1#2{%
    \pgfkeysdef{#1}{%
      \@ifnextchar[%
        {\pgfkeysvalueof{#1/@cmd@with@optarg}}%
        {\pgfkeysvalueof{#1/@cmd@with@optarg}[#2]}%
      ##1\pgf@nil
    }%
  }
  \pgfkeys{
    /handlers/.code with optarg with default value/.code 2 args={%
      \long\def\mypgfkeys@temp[##1]##2\pgf@nil{#2}%
      \pgfkeyslet{\pgfkeyscurrentpath/@cmd@with@optarg}\mypgfkeys@temp
      \expandafter\expandafter\expandafter\mypgf@install@code@with@optarg
      \expandafter\expandafter\expandafter{\pgfkeyscurrentpath}{#1}%
    },
    /handlers/.code with optarg/.code={%
      \pgfkeys{\pgfkeyscurrentpath/.code with optarg with default value={}{#1}}%
    },
    /handlers/.style with optarg with default value/.code 2 args={
      \pgfkeys{\pgfkeyscurrentpath/.code with optarg with default value={#1}{\pgfkeysalso{#2}}}%
    },
    /handlers/.style with optarg/.code={%
      \pgfkeys{\pgfkeyscurrentpath/.code with optarg with default value={}{\pgfkeysalso{#1}}}%
    },
  }
\makeatother

\begin{document}

\pgfkeys{
  one/.code with optarg with default value={default}{#1::#2\par},
  two/.code with optarg={#1::#2\par},
  one=normal,             % prints "default::normal"
  one=[optional]normal,   % prints "optional::normal"
  two=normal,             % prints "::normal"
  two=[optional]normal,   % prints "optional::normal"
}

\end{document}

相关内容