来自pgfkeys.code.tex
文件:
% This is useful:
\def\pgfkeys@ifcsname#1\endcsname#2\else#3\fi{\expandafter\ifx\csname#1\endcsnam
e\relax#3\else#2\fi}%
\ifx\eTeXrevision\undefined%
\else%
\expandafter\let\expandafter\pgfkeys@ifcsname\csname ifcsname\endcsname%
\fi
该命令\pgfkeys@ifcsname
在内部用于检查密钥是否存在。如果etex
存在,则只需执行\ifcsname
。如果不存在,则这是一个后备方案,在使用它的情况下,该方案被认为足够好。
但是,它不能很好地与嵌套条件配合使用。有时它通过另一个命令使用:
\long\def\pgfkeysifdefined#1#2#3{\pgfkeys@ifcsname pgfk@#1\endcsname#2\else#3\fi}
这里的问题是,如果#2
或#3
包含另一个条件,则因为\pgfkeys@ifcsname
使用宏参数匹配而不是条件匹配,所以\else
或\fi
中的#2
或#3
可以匹配而不是给定的或。添加括号不起作用,因为那会增加一组额外的括号。
现在,我打算在 PGF 错误列表中报告此问题,但我认为我应该先尝试提出替代方案。
我想到的是:
\def\pgfkeys@ifcsname#1\endcsname{\ifx\csname#1\endcsname\relax\expandafter\iffalse\else\expandafter\iftrue\fi}
所以我的问题是:这款产品是否还存在原来没有遇到的问题?
(因此,使其\csname undefinedcommand\endcsname
成为\undefinedcommand
并不\relax
反对新定义,因为它在原始定义中已经存在。)
答案1
PGF代码在很多方面都是错误的。
\else
当宏嵌套在其他条件中使用时,用and限定参数\fi
没有帮助。如果参数是,则宏会给出不同的结果
relax
,取决于 e-TeX 是否可用。
我会使用通常的间接方法:
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\def\@pgfkeys@csname#1\endcsname{%
TT\fi
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
\iffalse\iftrue
}
用作
\if\@pgfkeys@csname something\endcsname
true case%
\else
false case%
\fi
有不定义在嵌套条件中正确运行的“宏条件”的方法。另一种方法是使用 LaTeX 样式的参数条件,使用通常的\@firstoftwo
and \@secondoftwo
,基本上与
\@ifundefined{macro}
{<not defined or \relax case>}
{<defined and not \relax case>}
很容易“反转”这个来获得\@ifdefined
宏,只需在 的定义中交换\@firstoftwo
和 即可。\@secondoftwo
\@ifundefined
答案2
需要注意的是,无论 的定义如何\pgfkeys@ifcsname
,它都不能安全地在另一个 TeX 条件中使用:尝试这样做\if[...]\pgfkeys@ifcsname...\endcsname...\fi...\fi
会导致第一个\fi
关闭 ,第二个\fi
关闭\if
,而第二个\fi
则未使用。但是, 的当前定义\pgfkeys@ifcsname
甚至不允许在其分支中使用其他 TeX 条件,这个问题可以修复。
首先说一句小话:你可能忘了在定义中把 放在\expandafter
前面,以扩展。让我们把它放回去:\ifx
\csname
\def\pgfkeys@ifcsname#1\endcsname
{%
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\iffalse
\else
\expandafter\iftrue
\fi
}
我选择的布局符合预期:如果构造\csname#1\endcsname
结果为\relax
,则我们要调用\iffalse
并采取随后的错误分支(因为命令#1
未定义),否则调用\iftrue
。不幸的是,这失败了。
- 如果命令不存在,则
\ifx
测试为真,TeX 看到\expandafter
,扩展\else
,这会导致它跳转到匹配的\fi
,但是......没有匹配的\fi
,因为 TeX 将其视为\iftrue\fi
嵌套条件。 - 如果命令存在,则
\ifx
测试为假并尝试跳转到以下\fi
。但它看到一个\iffalse
条件,一个\iftrue
,\fi
匹配的\iftrue
,并且必须还有两个来\fi
关闭\if...
s 。
有几种方法可以避免混淆条件:
\def\pgfkeys@ifcsname#1\endcsname
{%
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
\iffalse\iftrue
}
和定义为 LaTeX 中的和。\@firstoftwo
或者\@secondoftwo
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\def\pgfkeys@ifcsname#1\endcsname
{%
\csname
\expandafter\ifx\csname#1\endcsname\relax
iffalse%
\else
iftrue%
\fi
\endcsname
}
为了更加强大,甚至可以避免使用以\endcsname
辅助函数为代价来分隔的参数:
\def\pgfkeys@ifcsname{\expandafter\pgfkeys@ifcsname@\csname}
\long\def\pgfkeys@ifcsname@#1%
{%
\csname
\ifx#1\relax
iffalse%
\else
iftrue%
\fi
\endcsname
}
这里我决定把它做\pgfkeys@ifcsname@
长,以防测试的控制序列恰好是\par
。