以下代码不会产生任何错误并且运行良好:
\documentclass{memoir}
\def\ThingyFred {This is the thingy named Fred}
\begin{document}
\chapter{Fred}
\ThingyFred
\end{document}
下面的代码给出了错误
"Undefined control sequence. \ThingyJoe"
,
这正是我所期望并希望它能做到的:
\documentclass{memoir}
\def\ThingyFred {This is the thingy named Fred}
\begin{document}
\chapter{Fred}
\ThingyJoe
\end{document}
但出于各种原因,我想(在文档主体中)引用诸如 之类的内容\Thingy{Fred}
,而不是\ThingyFred
。以下方法可以正常工作:
\documentclass{memoir}
\def\RawThingyFred {This is the thingy named Fred}
\def\Thingy#1 {\csname RawThingy#1\endcsname}
\begin{document}
\chapter{Fred}
\Thingy{Fred}
\end{document}
但是,与我天真的期望和希望相反,下面的代码确实不是给出一个错误(它反而将其\Thingy{Joe}
视为一个空变量):
\documentclass{memoir}
\def\RawThingyFred {This is the thingy named Fred}
\def\Thingy#1 {\csname RawThingy#1\endcsname}
\begin{document}
\chapter{Fred}
\Thingy{Joe}
\end{document}
经过进一步调查后,我发现问题在于,当你执行 时\Thingy{Joe}
,\def\Thingy#1 \csname RawThingy#1\endcsname
不仅仅会转化为\RawThingyJoe
,而且还会转化为定义 \RawThingyJoe
例如,以下内容返回我希望的错误:
\documentclass{memoir}
\def\RawThingyFred {This is the thingy named Fred}
\def\Thingy#1 {\csname RawThingy#1\endcsname}
\begin{document}
\chapter{Fred}
\RawThingyJoe
\Thingy{Joe}
\end{document}
但以下操作不会出现错误:
\documentclass{memoir}
\def\RawThingyFred {This is the thingy named Fred}
\def\Thingy#1 {\csname RawThingy#1\endcsname}
\begin{document}
\chapter{Fred}
\Thingy{Joe}
\RawThingyJoe
\end{document}
因此,在第一种情况下,它似乎看到了\RawThingyJoe
,但不知道这意味着什么,而在第二种情况下,它看到了\Thingy{Joe}
,并决定\RawThingyJoe
意味着一个空字符串,并且然后看到\RawThingyJoe
,它将其解释为空字符串。
有没有办法采用“定义一个接受参数的宏”路线,但仍然得到我期望的错误检查?
答案1
正如 egreg 所写,\csname
... \endcsname
将控制序列标记定义为\let
-equivalent ,\relax
如果它尚未定义(您可以将其视为 的副作用\csname
)。使用 e-TeX 扩展,您可以使用 来\ifcsname
测试控制序列是否已定义,而无需定义它(无副作用):
\documentclass{article}
\newcommand*{\RawThingyFred}{This is the thingy named Fred}
\newcommand*{\Thingy}[1]{%
\ifcsname RawThingy#1\endcsname
\csname RawThingy#1\endcsname
\else
\errmessage{\string\RawThingy#1 is undefined}%
\fi
}
\begin{document}
\Thingy{Fred}% okay
\Thingy{Joe}% prints \RawThingyJoe is undefined.
\end{document}
您可以查看此类测试的其他技术这里。
PS:我将您的\def
s 更改为\newcommand*
,首先是因为\newcommand
并\newcommand*
确保您不会意外覆盖现有的宏,其次是因为您的参数文本中有一个可能不需要的空格(例如,在 之后#1
)\def\Thingy#1 {...}
。