这个问题类似于如何在 LaTeX 中有条件地定义新命令?但我想测试命令的星号版本是否已定义。
天真的事
\makeatletter
\@ifundefined{ref*}{}{}
\makeatother
\ref
例如,对于测试的星号版本是否被定义(比如,由)它不起作用,hyperref
因为它总是返回 true。
答案1
一般情况下,命令没有带星号的版本。实际上,不带星号的命令会检查第一个参数是否为星号,并相应地将控制权交给不同的辅助宏,或者直接执行两组不同的命令。
因此,随便举一个例子,我们看一下\endlargethispage
并发现它的定义是:
\gdef \enlargethispage {%
\@ifstar
{%
\@enlargepage{\hbox{\kern\p@}}}%
{%
\@enlargepage\@empty}%
}
这\@ifstar
是检测流浪星的关键。
从这个例子中可以清楚地看出,没有简单的测试来判断是否\enlargethispage*
有效。我能想到的最精确的测试是检查\meaning\enlargethispage
是否存在\@ifstar
,但即使这样也无法捕获所有内容(\let\my@ifstar=\@ifstar
),也可能产生误报(因为\meaning
转换为字符的标记列表,因此在其中寻找精确的标记可能会被欺骗)。但这实施起来会很复杂,也许有一种更简单的方法来实现您想要实现的目标。
答案2
这基本上是不可能的,我将尝试通过一个例子来解释原因。
让我们\show\section
:
\section=\long macro:
-> \@startsection {section}{1}{\z@ }{-3.5ex \@plus
-1ex \@minus -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }
好吧,除此之外没什么可看的\section
根本不接受任何争论!让我们\show\@startsection
:
\@startsection=macro:
#1#2#3#4#5#6->\if@noskipsec \leavevmode \fi \par \@tempskipa #4\relax \@afterindenttrue
\ifdim \@tempskipa <\z@ \@tempskipa -\@tempskipa \@afterindentfalse \fi
\if@nobreak \everypar {}\else \addpenalty \@secpenalty \addvspace \@tempskipa \fi
\@ifstar {\@ssect {#3}{#4}{#5}{#6}}{\@dblarg {\@sect {#1}{#2}{#3}{#4}{#5}{#6}}}
瞧!\@ifstar
定义中的\@startsection
告诉你\section
有一个带星号的变体。它是如何工作的?请注意\section
传递给\@startsection
所有 6 个强制参数,因此如果你写\section*{BLA}
,它就变成\@startsection{<6 arguments>}*{BLA}
,而这变成blablabla \@ifstar {\@ssect {#3}{#4}{#5}{#6}}{\@dblarg {\@sect {#1}{#2}{#3}{#4}{#5}{#6}}}*{BLA}
。最后,\@ifstar
是一个疯狂的命令,它有两个参数,如果*
遵循则使用第一个参数,否则使用第二个参数。
因此,如您所见,检查命令的星号变体是否已定义确实不是一件简单的事情。更不用说\@ifstar
不是定义命令的星号变体的唯一方法。问题是星号是不是命令名称的一部分, 这是第一个可选参数。