我正在尝试这个:
\documentclass{article}
\begin{document}
\expandafter\newcommand\csname foo\endcsname{}
\expandafter\newcommand*\csname bar\endcsname{}
\end{document}
第二个\newcommand*
不起作用:
! LaTeX Error: Command \csname already defined.
Or name \end... illegal, see p.192 of the manual.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.4 \expandafter\newcommand*\csname b
ar\endcsname{}
我没能找到这个问题。
答案1
\newcommand*
是二令牌,所以你需要一个\expandafter
来跳过*
,所以
\expandafter\newcommand\expandafter*\csname foo\endcsname{<replacement text>}
另一方面,\newcommand*
对于无参数宏来说,使用它毫无意义;如果你想检查用定义的宏是否\newcommand
有空的替换文本,那么你可以使用\ifdefempty
或\ifcsempty
测试etoolbox
,或者定义你自己的空“长”宏版本
\newcommand\yegorempty{}
然后,用 定义的\newcommand
带有空替换文本的宏将等于(\yegorempty
如果用 进行测试)\ifx
。
答案2
值得注意的是,有用于此目的的内部 LaTeX 命令:
\@namedef{NAME}{...}
定义\NAME
为命令。这些是 TeX 原语的薄包装器\def
,因此如果您想要有参数,则需要使用纯语法,例如,对于三参数命令:
\@namedef{NAME}#1#2#3{...}
这将等效于¹\newcommand*{\NAME}[3]{...}
或\NewDocumentCommand{\NAME}{mmm}{...}
\newcommand
不带*
或\NewDocumentCommand
指定+m
而不是m
可以使用以下方式实现:
\long\@namedef{NAME}...
根据您的需要,这可能是一种更合适的方法。
为了扩展 John Kormylo 的回答,下面是使用更简单的²等效方法\NewDocumentCommand
代替\newcommand
:
\NewDocumentCommand{\NewNameDocumentCommand}{m}
{%
\expandafter\NewDocumentCommand\csname #1\endcsname
}
不完全是,在实际进行定义之前
\newcommand
检查命令是否存在,而并不关心。\@ifdefinable
\@namedef
主要是因为
\NewDocumentCommand
使用了比更灵活的方法来区分长参数和短参数,\newcommand
因此没有形式*
。也就是说,如果我们想精确复制约翰的定义\newcommand
,我们可以这样写:³\NewDocumentCommand{\Newcommand}{sm} {% \IfBooleanTF{#1}% {\expandafter\newcommand\expandafter*\csname #2\endcsname}% {\expandafter\newcommand\csname #2\endcsname}% }
比较这两个定义应该可以清楚说明为什么我如此支持
\NewDocumentCommand
,\newcommand
尤其是因为前者已经成为 LaTeX 内核的一部分近一年了。
答案3
我还创建了自动\Newcommand
应用\csname
。事实证明,内部\newcommand
转换\foo
为\\foo
,因此拥有名称不会节省任何步骤。
\documentclass{article}
\expandafter\newcommand\csname foo\endcsname{test 1}
\expandafter\newcommand\expandafter*\csname foobar\endcsname{test 2}
\makeatletter
\def\Newcommand{\@ifstar\@Newcommandstar\@Newcommand}
\def\@Newcommand #1{\expandafter\newcommand\csname #1\endcsname}
\def\@Newcommandstar #1{\expandafter\newcommand\expandafter*\csname #1\endcsname}
\makeatother
\Newcommand{Foo}{test 3}
\Newcommand*{Foobar}{test 4}
\begin{document}
\foo
\foobar
\Foo
\Foobar
\end{document}
答案4
如果避免使用 LaTeX 语法并直接使用 TeX 语法,事情会更简单:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\sdef{foo}{test}
\long\sdef{Foo}{test2}
\meaning\foo, % normal macro \foo expands to test
\meaning\Foo. % long macro \Foo expands to test2
\bye
当然,您可以\sdef
像在原始宏中一样使用带参数的 -ed 宏\def
,或者使用\global
前缀。