使用 csname 创建新命令时需要使用括号

使用 csname 创建新命令时需要使用括号

为什么\expandafter\newcommand\csname hello\endcsname{Hello world}创建新的宏时会\expandafter\newcommand{\csname hello\endcsname}{Hello world}产生垃圾?

根据我的理解,\csname hello\endcsname以编程方式创建一个可用作命令名称的新字符串,在本例中,类似于\hello。您可以同时编写\newcommand\hello{Hello world}\newcommand{\hello}{Hello world},它们都可以工作。那么为什么在涉及 csname 时,我必须使用不带花括号的形式来括住名称呢?

答案1

的“官方”语法\newcommand

\newcommand{<macro name>}[<args>]{<text>}

或者

\newcommand{<macro name>}[<args>][<default>]{<text>}

但事实证明,<macro name>只要出现一个标记,括号周围的括号是可选的。括号有助于避免错误,但一些自我控制通常就足够了。

\expandafter\newcommand\csname hello\endcsname{world}

令牌在开始行动并吸收其第一个参数\hello之前被构建\newcommand(实际上,故事很长,但这个简短的解释足够精确)。

另一方面,

\expandafter\newcommand{\csname hello\endcsname}{world}

将尝试扩展括号:\expandafter仅对单个标记起作用,如果标记可扩展,则触发其扩展,否则不执行任何操作。你如果你愿意的话,可以使用大括号,但是你还需要\expandafter

\expandafter\newcommand\expandafter{\csname hello\endcsname}{world}

然而,对于这样一个简单的结构来说,这也太多了,不是吗?

如果你发现自己必须做几个这样的定义,那么构建一个包装器就“很容易”了

\makeatletter
\newcommand\newnamecommand{\@star@or@long\new@name@command}
\newcommand\new@name@command[1]{\expandafter\new@command\csname #1\endcsname}
\newcommand\renewnamecommand{\@star@or@long\renew@name@command}
\newcommand\renew@name@command[1]{\expandafter\renew@command\csname #1\endcsname}
\newcommand\providenamecommand{\@star@or@long\provide@name@command}
\newcommand\provide@name@command[1]{\expandafter\provide@command\csname #1\endcsname}
\makeatother

\newnamecommand{hello}{Hello World}
\newnamecommand*{helloarg}[1]{Hello #1}

\renewnamecommand{hello}{Whatever}

\providenamecommand{foo}{FOO}

答案2

您需要为 提供一个明确的控制序列\newcommand,并且\csname <text>\endcsname直到扩展之前它才是一个控制序列。

使用

\expandafter\newcommand\csname hello\endcsname{<stuff>}

扩展为

\newcommand\hello{<stuff>}

\expandafter这是跳过\newcommand并扩展\csname hello\endcsname到的结果\hello。然而,

\expandafter\newcommand{\csname hello\endcsname}{<stuff>}

扩展为

\newcommand{\csname hello\endcsname}{<stuff>}

as{不可扩展,因此\expandafter毫无用处。如果您想使用“分组接口\newcommand”,则需要额外的\expandafter

\expandafter\newcommand\expandafter{\csname hello\endcsname}{<stuff>}

但是,如果没有它,\newcommand就会失败,因为没有明确的控制序列。

etoolbox\@namedef{<csname>}通过与 LaTeX 内核的接口提供了一种解决此问题的方法latex.ltx):

\csdef{<csname>}<args>{<stuff>}

也就是说,你可以使用

\csdef{hello}<args>{<stuff>}

<args>以上是可选的,但采用\def参数指定(或模式)的形式。也就是说,#1而不是[1]说。

相关内容