如何用变量名定义 newcommand*?

如何用变量名定义 newcommand*?

我正在尝试这个:

\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
   }

  1. 不完全是,在实际进行定义之前\newcommand检查命令是否存在,而并不关心。\@ifdefinable\@namedef

  2. 主要是因为\NewDocumentCommand使用了比更灵活的方法来区分长参数和短参数,\newcommand因此没有形式*。也就是说,如果我们想精确复制约翰的定义\newcommand,我们可以这样写:³

    \NewDocumentCommand{\Newcommand}{sm}
      {%
        \IfBooleanTF{#1}%
          {\expandafter\newcommand\expandafter*\csname #2\endcsname}%
          {\expandafter\newcommand\csname #2\endcsname}%
      }
    
  3. 比较这两个定义应该可以清楚说明为什么我如此支持\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前缀。

相关内容