具有多个参数的宏的定义和 \csname 的用法

具有多个参数的宏的定义和 \csname 的用法

为什么下面的代码不起作用?

\Requirepackage{amsthm}
\renewcommand\newtheorem[2]{%
    \NewEnviron{\csname #1\endcsname}[1]{%
        ##1 : \BODY
    }
}

我见过使用\csname SOMENAME\endcsname不带参数的 for 宏的示例,但我不知道如何使用带有多个参数的\NewEnviron或 来执行此操作\newcommand。系统提示我出现错误! Missing \endcsname inserted

答案1

您不需要将命令名称用作环境名称。只要名称即可。

因此,你可以这样做:

\documentclass{article}
\usepackage{amsthm,environ}
\renewcommand\newtheorem[2]{%
    \NewEnviron{#1}[1]{%
        ##1 : \BODY
    }%
}
\begin{document}
\newtheorem{acorns}{oaks}
\begin{acorns}{trees}
  leaves and things
\end{acorns}
\end{document}

请注意,此代码不需要阿姆斯特丹\newcommand\newtheorem...,除非您因为其他原因需要该包,否则您可以使用。

此外,即使您创建了命令,第二个参数也是必需的,但您永远不会对它执行任何操作。在上面的例子中,对 执行了任何操作oaks

我不确定这是否真的是你想要做的。上述代码的输出是:

树木、树叶和其他东西

作为Christian Hupfer 指出,这当然会破坏\newtheorem标准意义上的一切使用。埃格尔说,完全看不出\newtheorem这种重新定义的目的是什么。这似乎迟早会惹上麻烦……可能很快就会。

答案2

为什么下面的代码不起作用?

让我们仔细看看\NewEnviron

经过一个简短的宏链来正确解析用户输入后,就开始\NewEnviron使用了。\env@newenvironment\let\newenvironment

现在,\newenvironment内部除了其他事情外(稍微简化了)还做了类似的事情

\expandafter\def\csname <env-name>\endcsname{<begin-code>}

(基本上,你做了正确的事情,但你不知道内部人员已经在处理这个问题了。)

如果您设置“ <env-name>=\csname SOMENAME\endcsname”——这将导致使用您的自定义宏\newtheorem{SOMENAME}{}——您最终会得到一对多余的\csname...\endcsname

\expandafter\def\csname\csname SOMENAME\endcsname\endcsname...

\expandafter(您可能知道)在这种情况下,它会抓取\def并存储它以向前查看下一个标记并首先扩展它。在这里,它会查找\csname下一个标记\endcsname并扩展其间的所有内容,并从中形成一个控制序列。这将是另一个\csname再次被尾随的正确终止的标记\endcsname。因此,您实际上将\csname机制两次应用于“SOMENAME”,这意味着您最终不会得到\def\SOMENAME{<begin-code>}(如您计划的那样),而是

\def\<expansion of \SOMENAME>{<begin-code>}

如果\SOMENAME定义了,我们就不会有问题:

\documentclass{article}
\usepackage{environ}

\def\SOMENAME{somename}
\NewEnviron{\csname SOMENAME\endcsname}{somename-content: \BODY}

\begin{document}
\begin{somename}
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  Integer feugiat tempus urna, cursus placerat sapien mollis ac.
  Donec a accumsan orci, in tristique ligula.
\end{somename}
\end{document}

但你应该不是定义它;这个用户界面可能会产生误导。只需使用与输入环境名称\NewEnviron完全相同的方式:\newenvironment

\documentclass{article}
\usepackage{environ}

\newcommand{\FlorianEnvdefWrapper}[1]{%
  \NewEnviron{#1}[1]{##1: \BODY}
}

\FlorianEnvdefWrapper{somename}

\begin{document}
\begin{somename}{foo-bar}
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  Integer feugiat tempus urna, cursus placerat sapien mollis ac.
  Donec a accumsan orci, in tristique ligula.
\end{somename}
\end{document}

评论

我更改了示例宏的名称以避免与amsthm包发生冲突。我认为总体上最好保持原样。当然也有例外,但如果您可以通过为命令选择另一个名称来避免这种情况,那么完全失去其功能可能不是最好的选择。

相关内容