以安全的方式测试 pgfkey 是否为空

以安全的方式测试 pgfkey 是否为空

我有这个小例子来检查键是否为空:

\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\makeatletter

\newcount\cnt\cnt=0\relax
\tikzset{dir/.is family}
\tikzset{dir/t0/.initial={}}

\begin{document}

% \tikzset{dir/t0={\small SMALL}}

Key \the\cnt is: \pgfkeysvalueof{/tikz/dir/t\the\cnt}

\edef\mykey{x\pgfkeysvalueof{/tikz/dir/t\the\cnt}}
\edef\plainx{x}
\ifx\plainx\mykey
    key t\the\cnt{} is empty
\else
    key t\the\cnt{} is not empty
\fi

\end{document}

并且它有效,除非我在键本身中放置一个字体更改命令(取消注释tikzset):

! TeX capacity exceeded, sorry [input stack size=5000].
\@setfontsize #1#2#3->\@nomath #1
                                 \ifx \protect \@typeset@protect \let \@curr...
l.18 ...ykey{x\pgfkeysvalueof{/tikz/dir/t\the\cnt}
                                                  }
!  ==> Fatal error occurred, no output PDF file produced!

我如何才能安全地检查密钥是否已设置为{}?我需要使用核心包来执行此操作,代码必须与 LaTeX 和 ConTeXt 兼容...

答案1

字体更改命令(现在)很强大,因此如果您使用\protected@edef而不是普通的\edef,则 LaTeX 的保护机制将启动并阻止 的扩展\small。但是,这仅在键包含强大或可扩展的命令时才有效(通常情况并非如此)。

更可靠的方法是利用 的实现细节\pgfkeysvalueof,也就是\csname pgfk@<full path to key>\endcsname(经过一次扩展)。\csname扩展路径中的所有内容并生成控制序列(经过第二次扩展),然后再进行一次扩展(第三次)会产生密钥的内容,因此您可以使用:

\def\unexpandedvalueof#1{%
  \unexpanded
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter{\pgfkeysvalueof{#1}}}

扩大\pgfkeysvalueof3 倍并将结果留在里面\unexpanded,这样它就不会进一步扩大\edef

请注意,由于\pgfkeysvalueof直接使用\csname,如果键之前不存在,TeX 将\relax在扩展后退出,并且空性测试将返回 false。如果您希望它对未定义的键返回 true,则需要在\relax扩展存储键的实际控制序列之前检查:

\def\unexpandedvalueof#1{%
  \unexpanded\expandafter\expandafter
    \expandafter\rmano@valueof@chk\pgfkeysvalueof{#1}}
\def\rmano@valueof@chk#1{%
  \ifx\relax#1%
    \expandafter\pgfutil@firstoftwo
  \else
    \expandafter\pgfutil@secondoftwo
  \fi
    {{}}%
    {\expandafter{#1}}}

这是一个可编译的示例:

\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{unravel}
\makeatletter

\newcount\cnt\cnt=0\relax
\tikzset{dir/.is family}
\tikzset{dir/t0/.initial={}}

\begin{document}

\tikzset{dir/t0={\small SMALL}}

Key \the\cnt is: \pgfkeysvalueof{/tikz/dir/t\the\cnt}

\makeatletter
\newcommand\unexpandedvalueof[1]{%
  \unexpanded\expandafter\expandafter
    \expandafter\rmano@valueof@chk\pgfkeysvalueof{#1}}
\def\rmano@valueof@chk#1{%
  \ifx\relax#1%
    \expandafter\pgfutil@firstoftwo
  \else
    \expandafter\pgfutil@secondoftwo
  \fi
    {{}}% #1 is \relax, so consider empty
    {\expandafter{#1}}}% otherwise, leave the key after one more expansion
\makeatletter

\edef\mykey{x\unexpandedvalueof{/tikz/dir/t\the\cnt}}
\edef\plainx{x}
\ifx\plainx\mykey
    key t\the\cnt{} is empty
\else
    key t\the\cnt{} is not empty
\fi

\edef\mykey{x\unexpandedvalueof{/tikz/dir/tBOO}}
\edef\plainx{x}
\ifx\plainx\mykey
    key t\the\cnt{} is empty
\else
    key t\the\cnt{} is not empty
\fi

\end{document}

ConTeXt 重命名了\unexpanded原语,因此您需要改用\normalunexpanded。您可以使用此代码定义泛型\pgfutil@unexpanded

\ifcsname normalunexpanded\endcsname
  \let\pgfutil@unexpanded\normalunexpanded
\else
  \let\pgfutil@unexpanded\unexpanded
\fi

相关内容