语境
请考虑以下情况。
\documentclass{minimal}
\makeatletter
\expandafter\def\csname/test\endcsname{%
\foo{bar}}
\def\mymacro#1{%
% Note the / *after* #1
\expandafter\expandafter\expandafter\mymacro@i\csname/#1/\endcsname}
\def\mymacro@i\foo#1{%
\def\temp{#1}%
\show\temp}
\mymacro{test}
% Error: Use of \mymacro@i doesn't match its definition.
\begin{document}
\end{document}
我在之前\mymacro
添加的定义中犯了一个拼写错误。显示的错误让我相信这三个错误扩展了,但是/
\endcsname
/test
\expandafter
我错了。由于/test/
未定义,它会默默扩展为\relax
,并且是的,因为我用而不是来喂它,TeX
所以说是正确的。Use of \mymacro@i doesn't match its definition
\relax
\foo
问题
这种\csname
定义的控制序列(即在\relax
未定义时扩展)的行为确实很方便,但有时我想停用它并可能发出错误Undefined control sequence
。 可能吗?
答案1
您无法改变的行为\csname
,但您可以使用 e-TeX\ifcsname
发出错误:
\csname
\ifcsname#1\endcsname
\else
\expandafter\UndefinedName
\fi
#1%
\endcsname
其中\UndefinedName
是故意不定义的。TeX 随后会发出一个错误,抱怨Undefined control sequence
,然后是#1
(这才是您真正想要抱怨的)。
(与 不同\@ifundefined
,\ifcsname
是可扩展的并且不会添加到哈希表中。)
答案2
您可以检查命令是否存在并自行调用错误。
\@ifundefined{/#1/}{%
\GenericError{}{%
Command /#1/ undefined!
}{%
See the definition of \protect\mymacro!
}
}{}%
该\@ifundefined
宏使用,\csname
因此它将宏定义为\relax
。我不认为这是一个问题(无论如何我们都会调用错误),但您可以用 包围代码以\begingroup ... \endgroup
使定义成为本地的。
答案3
问题中写道:
\csname 定义控制序列的这种行为(即未定义时扩展为 \relax)确实很方便,但有时我想停用它,并可能发出未定义的控制序列错误。可能吗?
\csname
用于从标记序列中获取控制序列标记,这些标记在扩展的某个阶段会产生一个字符标记序列,代表所讨论的控制序列标记的名称。如果所讨论的控制序列标记在应用时未定义\csname
,则会为其分配 -primitive 的含义\relax
。(即使 -parameter\globaldefs
具有正值,该分配也仅限于当前范围。)
因此,在这种情况下,\csname
-定义的控制序列不会扩展为。它根本不会扩展,因为它不可扩展,因为它具有与不可扩展标记的-原\relax
语相同的含义。\relax
用 来“命中”不可扩展标记\expandafter
不会影响这些标记。\expandafter
本身是可扩展的。所有扩展都在 TeX 的口中进行。因此处理\expandafter
将在 TeX 的口中进行。不可扩展标记不受此影响。它们到达 TeX 的胃中。
\mymacro@i
预计由控制字标记界定,\foo
而第一个-chain 来自“命中”\expandafter
的扩展,这反过来又提供不可扩展的控制字标记,其含义等于不可扩展的 -primitive 的含义。当被第二个 -chain “命中”时,该不可扩展的控制字标记不受影响。\mymacro{test}
\csname
\/test/
\relax
\expandafter
顺便说一句 1:对于带分隔符的参数,TeX 通常在收集参数时会删除参数分隔符。因此,在收集参数时,参数分隔符的含义并不重要。您甚至可以愉快地使用未定义的符作为参数分隔符。
顺便说一句 2:不要使用 minimal 类来制作最小示例。请改用 article 类。minimal
类是由 LaTeX2e 包的开发人员编写的,用于测试 LaTeX2e 包的类加载机制。