运行以字符串形式给出其名称的命令

运行以字符串形式给出其名称的命令

有没有办法定义这样的命令\escape,以便它可以运行具有给定名称的命令?例如,\escape{foo}将执行命令\foo,可能带有参数。

答案1

我想你只是想要\@namueuse

  • \@nameuse{foo}变成\foo

  • {\@nameuse{newcommand}}{\hi}{hi}实际意思是{\newcommand}{\hi}{hi},这是一个错误。但我认为这只是问题中的一个错误,而你是故意的 \escape{newcommand}{\hi}{hi}(没有括号)。

使用

\makeatletter
\let\escape=\@nameuse
\makeatother

或者直接跳到简单的定义\@nameuse

\newcommand*\escape[1]{\csname #1\endcsname}

答案2

我可以提供一个宏\CsNameToCsToken

\CsNameToCsToken{foo}\foo  。

(如果这适合您的需要,您可以用 替换\CsNameToCsToken\escape但我认为名称“CsNameToCsToken”更能描述所讨论的宏的作用。)

句法:

\CsNameToCsToken⟨stuff not in braces⟩{⟨NameOfCs⟩}

⟨stuff not in braces⟩\NameOfCs

⟨stuff not in braces⟩可能为空。)

定义(在 LaTeX 2ε 中):

\begingroup
\makeatletter
\@firstofone{%
  \endgroup
  \@ifdefinable\CsNameToCsToken{%
    \long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
  }%
  \newcommand\InnerCsNameToCsToken[2]{%
    \expandafter\exchange\expandafter{\csname#2\endcsname}{\z@#1}%
  }%
  \newcommand\exchange[2]{#2#1}%
}%

在纯 TeX 中

  • 也可以定义\z@,例如,将其定义为扩展为 的宏,或者将其定义为表示保存长度值 0pt 的寄存器的 -token,0⟨explicit space token⟩\dimendef

  • 或者:

    \long\def\CsNameToCsToken#1#{\romannumeral0\InnerCsNameToCsToken{#1}}%
    \long\def\InnerCsNameToCsToken#1#2{%
      \expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}% <- the space before #1 must be!
    }%
    \long\def\exchange#1#2{#2#1}%
    

(由于\romannumeral-扩展,结果是通过触发两个扩展步骤获得的,例如,通过用 进行两次“命中” \expandafter。)

使用这样的宏,您就不会受到特定定义命令的约束:

\CsNameToCsToken{foo}\foo  。

\CsNameToCsToken\newcommand{foo}\newcommand\foo  。

\CsNameToCsToken\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  。

\CsNameToCsToken\global\long\outer\def{foo}\global\long\outer\def\foo  。

\CsNameToCsToken\expandafter{foo}\bar\expandafter\foo\bar  。

\CsNameToCsToken\let{foo}=\bar\let\foo=\bar  。

\CsNameToCsToken\string{foo}\string\foo  。

\CsNameToCsToken\meaning{foo}\meaning\foo  。


以下是所请求的\NewDocumentCommand示例:

实际上,\NewDocumentCommand您并不需要用括号括住控制序列标记来进行定义。

例如,
\NewDocumentCommand\foo{m}{foo's argument is: #1}

\NewDocumentCommand{\foo}{m}{foo's argument is: #1}

因此你可以这样做:

\CsNameToCsToken\NewDocumentCommand{foo}...\NewDocumentCommand\foo...  。


您也可以使用这样的宏来定义/调用名称包含空格的宏:

\CsNameToCsToken{foo }\foo␣  。

\CsNameToCsToken\newcommand{foo }\newcommand\foo␣  。

\CsNameToCsToken\DeclareRobustCommand{foo }\DeclareRobustCommand\foo␣  。

\CsNameToCsToken\global\long\outer\def{foo }\global\long\outer\def\foo␣  。

\CsNameToCsToken\expandafter{foo }\bar\expandafter\foo␣\bar  。

\CsNameToCsToken\let{foo }=\bar\let\foo␣=\bar  。

\CsNameToCsToken\string{foo }\string\foo␣  。

\CsNameToCsToken\meaning{foo }\meaning\foo␣  。

您还可以嵌套调用\CsNameToCsToken

示例 1:

   \CsNameToCsToken\CsNameToCsToken\expandafter{f o o }{b a r }

处理第一个\CsNameToCsToken收益:
   \CsNameToCsToken\expandafter\f␣o␣o␣{b a r }  。

处理第二个\CsNameToCsToken收益:
   \expandafter\f␣o␣o␣\b␣a␣r␣  。

(类似地:\CsNameToCsToken\CsNameToCsToken\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣。)

示例 2:

   \CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

处理第一个\CsNameToCsToken收益:
   \CsNameToCsToken\CsNameToCsToken\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  。

处理第二个\CsNameToCsToken收益:
   \CsNameToCsToken\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  。

处理第三个\CsNameToCsToken得到:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  。

示例 3:

在扩展上下文中,您可以使用\romannumeral-expansion 来使事情继续进行。

   \romannumeral\CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

\romannumeral触发扩展,直到 TeX 找到一个形成⟨数字⟩-quantity。最后 TeX 会找到⟨数字⟩-quantity\z@的值为,0而非正数则\romannumeral默默地吞噬形成⟨数字⟩-quantity 但根本不传递任何令牌:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

处理第一个\CsNameToCsToken收益:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  。

处理第二个\CsNameToCsToken收益:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  。

处理第三个\CsNameToCsToken得到:
   %\romannumneral-expansion in progress
   \z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  。

现在\romannumeral找到\z@,即数字0(以没有其他数字并且没有要丢弃的空间标记来终止⟨数字⟩将被搜索)。因此\romannumeral-expansion 被中止并且\romannumeral不会传递任何 token
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  :。

请注意,在应用时\CsNameToCsToken内部应用的副作用是,如果在应用之前未定义相关控制序列,则将 -primitive 的含义分配给相关控制序列。即使在应用时 -parameter 具有正值,该分配也将限制在当前范围内。\csname\csname\relax\csname\globaldefs\csname

相关内容