如何测试已知键值是否已在 pgfkeys 中设置

如何测试已知键值是否已在 pgfkeys 中设置

使用.code我的密钥的处理程序和私有宏,我可以轻松测试在使用时是否已设置密钥pgfkeys。例如:

\documentclass{article}
\newcounter{mytestenvcounter}
\usepackage{pgfkeys}
\makeatletter
\let\ae@mykey@test\relax
\def\ae@get@mykey@test{\ifx\ae@mykey@test\relax{I've not been set.}\else{I am set to:\ae@mykey@test}\fi}
\pgfkeys
  {
    /ae/mykeys/set/.cd,
    mykey/.code = {\def\ae@mykey@test{#1}},
    /ae/mykeys/get/.cd,
    mykey/.code = {\ae@get@mykey@test},
  }
\makeatother
\newenvironment{mytestenv}[1]
  {\pgfkeys{ /ae/mykeys/set/.cd, #1}%
   \begin{minipage}[t]{2in}%
   \stepcounter{mytestenvcounter}\themytestenvcounter.)\hspace*{0.5em}
   \pgfkeys{ /ae/mykeys/get/mykey }%
  }
  {\end{minipage}%
  }

\pagestyle{empty}
\begin{document}

  \begin{mytestenv}{mykey={testing}}
  \end{mytestenv}

  \begin{mytestenv}{}
  \end{mytestenv}

\end{document}

在对我之前的一个问题的评论中有人建议有一种更好的方法,即通过.initial测试空值。但我不知道如何实现这一点。

据我所知,这是如何获得的:

\documentclass{article}
\newcounter{mytestenvcounter}
\usepackage{pgfkeys}
\pgfkeys
  {
    /ae/mykeys/.cd,
    mykey/.initial=,
  }
\newenvironment{mytestenv}[1]
  {\pgfkeys{ /ae/mykeys/.cd, #1}%
   \begin{minipage}[t]{2in}%
   \stepcounter{mytestenvcounter}\themytestenvcounter.)\hspace*{0.5em}
   \pgfkeys{ /ae/mykeys/mykey }%
  }
  {\end{minipage}%
  }

\pagestyle{empty}
\begin{document}

  \begin{mytestenv}{mykey={testing}}
  \end{mytestenv}

  \begin{mytestenv}{}
  \end{mytestenv}

\end{document}

我曾尝试使用\pgfkeysifdefined,但似乎总是测试结果为阳性。

我也见过以下问题和答案,但不明白它与我想做的事情有什么关系。此外,在这个特定的问题和答案中,我不明白为什么需要\detokenize并且定义的语法\pgfkeysifstyleempty@i似乎不正确。所以,如果你想给我指出这个方向,我将非常感激你对那里发生的事情的评论。

但是,真的有必要定义一个宏来测试empty中的值吗pgfkeys?能够测试当前环境中是否已设置某个键似乎是相当合理的。我仔细阅读了手册pgfkeys中的章节tikz。但除了我上面提到的之外,那里似乎没有什么很有希望的。

答案1

\empty我认为,当未设置时使用稍微简单的方法就足够了,并且当它由 控制时,值位于某个宏中\if。但是它不一定是\empty。无论默认值是什么,您都可以对其进行测试。对于一般的错误处理和调试情况,寻找未定义的宏可能不是一个好主意。

\documentclass{article}
\usepackage{pgfkeys}
\newcounter{mytestenvcounter}
\newif\ifaevalueisset
\pgfkeys{
/ae/mykeys/mykey/.code={\ifx#1\empty\else%
                             \aevalueissettrue
                             \edef\mytempval{\ignorespaces#1}% optional ignorespaces
                       \fi},
/ae/mykeys/mykey/.default=\empty,
}
\newenvironment{mytestenv}[1][]
  {\pgfkeys{/ae/mykeys/.cd,#1}
   \begin{minipage}[t]{2in}%
   \stepcounter{mytestenvcounter}\themytestenvcounter.)\hspace*{0.5em}%
   \ifaevalueisset\mytempval\aevalueissetfalse\else\fi
  }
  {\end{minipage}%
  }
\begin{document}\pagestyle{empty}

  \begin{mytestenv}[mykey={testing}]
  \end{mytestenv}

  \begin{mytestenv}[mykey]a
  \end{mytestenv}

  \begin{mytestenv}
  \end{mytestenv}

  \begin{mytestenv}[mykey=different combos]
  \end{mytestenv}
\end{document}

在此处输入图片描述

答案2

以下代码提供了两个处理程序

  • .initial without value
  • .unset

两者都将键设置为\pgfkeys@notset宏的内容,如果使用宏,则会引发错误消息(或更糟的情况)。(宏\pgfkeysvalueof不会检查定义的键。)

处理程序与处理程序.initial without value非常相似.initial,只是覆盖了密钥,而密钥则.unset检查密钥是否实际定义(更多的是对于应该能够“取消设置”密钥的用户的处理程序)。

代码

\documentclass{article}
\usepackage{pgfkeys}
\makeatletter
\def\pgfkeys@@notset{\PackageError{pgfkeys}
  {The \pgfkeyscurrentpath\space key has not been set to a value.}{}}
\begingroup
  \lccode`\Q=`\-
  \lccode`\N=`\N
  \lccode`\V=`\V
  \lowercase{\endgroup
    \def\pgfkeys@notset{QNoValue-\pgfkeys@@notset}}
\def\pgfkeys@firstoftwo#1#2{#1}
\def\pgfkeys@secondoftwo#1#2{#2}
\pgfqkeys{/handlers}{%
  .initial without value/.code/.expand once=%
    \expandafter\pgfkeyssetvalue\expandafter{\expandafter\pgfkeyscurrentpath\expandafter}\expandafter{\pgfkeys@notset},%
  .unset/.code=%
    \pgfkeysifdefined{\pgfkeyscurrentpath}
      {\pgfkeys{\pgfkeyscurrentpath/.initial without value}}
      {\PackageError{pgfkeys}
        {The \pgfkeyscurrentpath\space key has not been initialized.}{}}%
}
\def\ifpgfkeyssetbyuser#1{%
  \expandafter\ifx\csname pgfk@#1\endcsname\pgfkeys@notset
    \expandafter\pgfkeys@secondoftwo
  \else
    \expandafter\pgfkeys@firstoftwo
  \fi}
\makeatother
\def\testkey#1{%
  \texttt{#1} is \ifpgfkeyssetbyuser{/#1}{set to ``\pgfkeysvalueof{/#1}''}{not set}.}
\begin{document}
% The \pgfkeyssetbyuser macro doesn't test
% whether the key it is actually defined, this results in "\relax"
\testkey{test} (\texttt{\char`\\relax})

\pgfkeys{test/.initial without value}
\testkey{test} % -> not set

\pgfkeys{test=1}
\testkey{test} % -> set to "1"

\pgfkeys{test=}
\testkey{test} % -> set to ""

\pgfkeys{test/.unset}
\testkey{test} % -> not set

\pgfkeys{test=-NoValue-}
\testkey{test}% -> set to "-NoValue-"

\pgfkeys{test/.unset}
\pgfkeysvalueof{/test} % -> "The /test key has not been set to a value."
                       % -> Output "-NoValue-"
\pgfkeys{testme/.unset}% -> "The /testme key has not been initialized."
\end{document}

输出

在此处输入图片描述

答案3

我个人使用 命令\pgfkeysifdefined来测试某个键是否已定义。为了使其正常工作,您需要使用 手动设置键\pgfkeyssetvalue,这可以通过键处理程序自动完成.code

{请注意在宏周围添加括号,}以便按照说明在本地设置密钥在这个关于 pgfkeys 范围的答案中

代码

\documentclass[varwidth,margin=0.5cm]{standalone}
\usepackage{pgfkeys}

\pgfkeys{%
  a/.code={\pgfkeyssetvalue{a}{#1}\pgfkeysgetvalue{a}{\a}},%
  b/.code={\pgfkeyssetvalue{b}{#1}\pgfkeysgetvalue{b}{\b}}}

\newcommand{\isDefined}[1][]{{% two braces to set the key locally
  \pgfkeys{#1}
  #1:\\
  \pgfkeysifdefined{a}{a is defined (a = \a)}{a is not defined}\\
  \pgfkeysifdefined{b}{b is defined (b = \b)}{b is not defined}}}

\begin{document}
  \isDefined[a=3]\smallskip\\
  \isDefined[b=2]\smallskip\\
  \isDefined[a]
\end{document}

输出

输出

答案4

考虑到与@Qrrbrbirlbel 的讨论以及如何xparse处理未定义的值,这是我想到的解决方案。

\documentclass{article}
\newcounter{mytestenvcounter}
\usepackage{pgfkeys}

\makeatletter
%%----------
\begingroup
  \lccode`\Q=`\-
  \lccode`\N=`\N
  \lccode`\V=`\V
  \lowercase{\endgroup
    \def\ae@unset@key@value{QNoValue-}}
%%----------
\def\ae@set@keys{\pgfqkeys{/ae/my/test/keys}}
\def\ae@test@getvalue#1{\pgfkeysgetvalue{/ae/my/test/keys/#1}}
\ae@set@keys
  {%
    mytestkey/.initial/.expand once=\ae@unset@key@value,
  }
\newenvironment{mytestenv}[1]
  {\ae@set@keys{#1}%
   \begin{minipage}[t]{2in}%
   \stepcounter{mytestenvcounter}\themytestenvcounter.)\hspace*{0.5em}
   \ae@test@getvalue{mytestkey}\@mytestkey@value
   \ifx\@mytestkey@value\ae@unset@key@value
      {I've not been set:}\else
      {I have been set:}\fi\@mytestkey@value
  }
  {\end{minipage}%
  }
\makeatother
\pagestyle{empty}

\begin{document}

  \begin{mytestenv}{}
  \end{mytestenv}

  \begin{mytestenv}{mytestkey={testing}}
  \end{mytestenv}

  \begin{mytestenv}{mytestkey={-NoValue-}}
  \end{mytestenv}

  \begin{mytestenv}{mytestkey={QNoValue-}}
  \end{mytestenv}

  \begin{mytestenv}{}
  \end{mytestenv}

\end{document}

这里的想法是使用\lccode值来创建一个极不可能传递给键的值(除非其他人\lccode在使用这种环境时也在做魔术)。

在此处输入图片描述

相关内容