使用.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
在使用这种环境时也在做魔术)。