\newcommand[.][.]{.} 定义的命令是否强大?

\newcommand[.][.]{.} 定义的命令是否强大?

这个问题来自 在 \textbf 中使用的 AM、PM 缩写(小型大写)。读者将从那里了解剩余的内容。

\newcommand\cmd[2][0]{\def\y{#1}}
\edef\x{\cmd{1}}

我明白了

{\edef}

\cmd ->\@protected@testopt \cmd \\cmd {0}

\@protected@testopt #1->\ifx \protect \@typeset@protect \expandafter \@testopt
\else \@x@protect #1\fi
#1<-\cmd
{\ifx}
{true}
{\expandafter}
{\else}

\@testopt #1#2->\kernel@ifnextchar [{#1}{#1[{#2}]}
#1<-\\cmd
#2<-0

\kernel@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reser
ved@b {#3}\futurelet \@let@token \@ifnch
#1<-[
#2<-\\cmd
#3<-\\cmd [{0}]

\reserved@a #11#2{->\expandafter \def \expandafter \\cmd \reserved@b #11{
! Argument of \reserved@a has an extra }.
<inserted text>
                \par
<to be read again>
                   }
l.3103 \edef\x{\cmd{1}}

? x

这就是稳健性吗?另请参阅是否有一个强大的 \renewcommand 替代品?

答案1

使用

\newcommand{\foo}[...][...]

\foo创建具有定义的宏

\@protected@testopt \foo \\foo {...}

在 LaTeX 的“受保护的扩展”命令(\protected@edef\protected@xdef\protected@write)中, 的定义\@protected@testopt被改变,使得不再发生进一步的扩展,因此

\protected@edef\test{\foo}
\show\test

给出

> \test=macro:
->\protect \foo .

\DeclareRobustCommand工作原理略有不同,因为

\DeclareRobustCommand{\foo}[...][...]

给出了定义

> \foo=macro:
->\protect \foo  .

该内部宏的名称中有一个空格:它被称为“ \foo”。在这里执行“受保护的扩展”可得到

> \test=macro:
->\protect \foo  .

IE保留了“带空格的名称”。由于此方法\protect比 使用的机制添加了“更早” \newcommand,因此它更加强大,但需要额外的 cname。

这两种机制都无法阻止在普通的\edef\xdef或内进行扩展。为此,您需要 e-TeX 保护机制,它以类似 的方式\write包装在\newcommand\newrobustcmdetoolbox包。在那里,做

\newrobustcmd{\foo}[...][...]

给出了定义

> \foo=\protected macro:
->\@testopt \\foo {...}.

这会绝不在扩展上下文中扩展,因为引擎正在进行保护。

答案2

“脆弱性”和“稳健性”的概念对于 LaTeX 来说是恰当的;稳健的命令是指在\protected@edef或 的替换文本中仍然存在的命令\protected@write。它具有没有什么\edef与 生存或有关\write.

例如,之后

\DeclareRobustCommand{\foo}[1][bar]{...}

就像是

\edef\baz{\foo[x]}

将会失败

! Argument of \reserved@a has an extra }

相反,\protected@edef\baz{\foo[x]}将赋予\baz意义

\protect \foo  [x]

(注意空格后\foo)。如果我们改为

\newcommand\foo[1][bar]{...}
\protected@edef\baz{\foo[x]}

的意思\baz

\protect \foo [x]

(后面只有一个空格\foo)。 强化方法不同,但同样有效。 必须注意的是,强化是不是\newcommand当为其简单形式时应用\newcommand\foo[n]{...}

当然,\protected给出了更高级的稳健性,因为用 定义的命令\protected\def甚至会存活下来\edef。但这是另一个故事。


它是如何工作的?\newcommand\foo[1][bar]{...}执行时,LaTeX 实际上会

\def\foo{\@protected@testopt \foo \\foo {bar}}

\expandafter\def\csname\string\foo\endcsname[#1]{...}

这与 LaTeX2.09 的方式非常相似

\def\foo{\@testopt\@foo{bar}}
\def\@foo[#1]{...}

但 has\@protected@testopt本质上是“如果\protect等于\relax,则执行\@testopt\\foo,否则输出\protect\foo”。处理诸如这样的“控制符号”有点复杂\?,但这几乎是事实。

答案3

此类宏使用 LaTeX 的保护机制,只能在\protected@edef和其他 LaTeX 宏(例如辅助文件写入宏)中工作,这些宏设置\protect得当。它们不适用于一般扩展上下文,例如\edef或普通\write

如果您需要定义一个带有可选参数的强健的 LaTeX 宏,请使用核心宏\DeclareRobustCommand\newrobustcmdetoolbox包中定义。

相关内容