为了防止在扩展上下文中扩展宏,我们可以将宏定义为\protected
。我想知道是否有办法对任意标记列表执行相同操作。
那么是否可以定义一个可以像下面这样\protecttoks
使用和工作的命令:\protecttoks{<token list>}
- 在正常执行模式下,它只是插入
<token list>
令牌流,以便它们可以正常执行。 - 在扩展模式下,它会扩展为自身,即未扩展的标记列表
\protecttoks{<token list>}
。
这个想法是能够将文字材料插入到标记列表中,但标记列表上完成的扩展的确切次数是事先不知道的。
编辑:也许关于以 LaTeX 为例的评论\protect
引起了混淆,我删除了它。关键是定义一些仍然能为 提供正确输出的东西\foo
,即使该命令在扩展后中断:
\def\foo{\textcolor{blue}{x}}
\edef\bar{\protecttoks{\foo}}
\edef\bar{\bar}
% more calls here ...
\edef\bar{\bar}
\bar
答案1
借助\protected
宏,您可以接近想要的结果。基本思路是先用一个\protected
宏,然后接另一个非\protected
宏。在\edef
(或\write
或\expanded
或...)中\protected
,TeX 将跳过该宏,而另一个宏将展开,只留下 (前面是\noexpand
)和\unexpanded{<stuff>}
。宏应该在其他地方\protected
展开,去掉未受保护的宏和一层括号。
基本设置是:
\protected\def\ifsafe#1#2{#2}
\def\elseifunsafe#1{\noexpand\elseifunsafe{\unexpanded{#1}}}
然后使用 as \ifsafe\elseifunsafe{<stuff>}
。在 中\edef
\ifsafe
不展开,并且\elseifunsafe
展开 并离开\elseifunsafe{<stuff>}
,因此您只剩下\ifsafe\elseifunsafe{<stuff>}
开始时的 。在其他地方\ifsafe
,展开消耗\elseifunsafe
和 周围的括号<stuff>
。
您可以\protecting
使用 定义一个宏\def\protecting{\ifsafe\elseifunsafe}
,但它会在第一个 之后消失\edef
,只留下实际的保护机制。
测试文档:
\protected\def\ifsafe#1#2{#2}
\def\elseifunsafe#1{\noexpand\elseifunsafe{\unexpanded{#1}}}
\def\protecting{\ifsafe\elseifunsafe}
\def\tmpa{\protecting{\something undefined}}\show\tmpa
\edef\tmpa{\tmpa 1}\show\tmpa
\edef\tmpa{\tmpa 2}\show\tmpa
\edef\tmpa{\tmpa 3}\show\tmpa
\tt
\detokenize\expandafter{\tmpa}\par
\detokenize\expandafter\expandafter\expandafter{\tmpa}
\bye
在终端中打印:
> \tmpa=macro:
->\protecting {\something undefined}.
l.8 ...protecting{\something undefined}}\show\tmpa
?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}1.
l.9 \edef\tmpa{\tmpa 1}\show\tmpa
?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}12.
l.10 \edef\tmpa{\tmpa 2}\show\tmpa
?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}123.
l.11 \edef\tmpa{\tmpa 3}\show\tmpa
?