有没有办法定义这样的命令\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