如何避免在使用‘\csname \endcsname’的宏中定义某些内容?

如何避免在使用‘\csname \endcsname’的宏中定义某些内容?

以下代码不会产生任何错误并且运行良好:

\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:我将您的\defs 更改为\newcommand*,首先是因为\newcommand\newcommand*确保您不会意外覆盖现有的宏,其次是因为您的参数文本中有一个可能不需要的空格(例如,在 之后#1\def\Thingy#1 {...}

相关内容