局部定义

局部定义

我知道如何定义宏如下

\newcommand{\mycommand}{ here my macro commands }

但我想创建一个定义宏的环境,如下所示

 \begin{definemycommand}{\mycommand}
  here my macro coomands
 \end{definemycommand}     

以便结果是一样的。

我尝试了一些非常愚蠢的事情,例如

 \newenvironment{definemycommand}[1]{\newcommand{#1}\{ }{ \} }

或者

 \newenvironment{definemycommand}[1]{\newcommand{#1}{ }{ } }

但显然这行不通,因为“{”和“}”无法像我希望的那样被识别。我怀疑有一个正确的方法来做到这一点。

答案1

对于这种用法,没有必要省略括号,例如:

\newenvironment{definemycommand}[1]{\newcommand{#1}\{ }{ \} }

那么,让我们看看你的第二次尝试:

\newenvironment{definemycommand}[1]{\newcommand{#1}{ }{ } }

这是不正确的,因为\newcommand不需要那么多参数(第二个参数{ }会留在输入流中,后面跟着一个可能不需要的空格标记)。更糟糕的是,\newenvironment需要两个论点在方括号内的参数数量后面的花括号中:一个用于开始,一个用于结束。

局部定义

\newcommand执行本地定义,因此,您不能\mycommand在环境之外使用以下内容:

\documentclass{article}

\newenvironment{definemycommand}[1]
  {\newcommand{#1}{here my macro commands}}
  {}

\begin{document}

\begin{definemycommand}{\mycommand}
  \mycommand
\end{definemycommand}

%\mycommand                      % ERROR: Undefined control sequence.

\end{document}

在此处输入图片描述

全局定义

如果您希望在环境结束后也能使用该命令,则可以使用\gdef。但是与 有一个明显的区别\newcommand(其中包括):\gdef不检查命令是否已存在。因此,它会在不通知的情况下覆盖现有的同名命令。如果您不想要这样,您可以使用\ifdefined ... \fi\ifcsname ... \endcsname ... \fi\else在每种情况下都是可选的)。

\documentclass{article}

\newenvironment{definemycommand}[1]
  {\gdef#1{here my macro commands}}
  {}

\begin{document}

\begin{definemycommand}{\mycommand}
  \mycommand
\end{definemycommand}

\bigskip
\mycommand                      % no problem

\end{document}

在此处输入图片描述

使用环境主体进行宏替换文本

如果你想使用环境主体作为宏替换文本,你可以这样做Phelype Oleinik 的回答或者使用environ包。我使用\unexpanded\expandafter{\BODY}以便只展开一次特殊宏(该宏由包中\BODY定义)。\NewEnvironenviron

\documentclass{article}
\usepackage{environ}

\NewEnviron{definemycommand}[1]
  {\xdef#1{\unexpanded\expandafter{\BODY}}}
  {}

\begin{document}

\begin{definemycommand}{\mycommand}
  here my macro commands
\end{definemycommand}

\mycommand

\end{document}

与第一个示例的输出相同:

在此处输入图片描述

注意环境主体开头和结尾可能存在的空格。使用诸如或 之X\mycommand X类的测试来检查环境定义的命令的精确行为或定义。在这种情况下,包似乎默认删除了空格,因此这种潜在的陷阱不适用。\show\mycommand\meaning\mycommanddefinemycommandenviron

使用改进etoolbox

以下是之前代码的一个变体:

  • 将命令名称作为参数没有前导反斜杠(我使用etoolbox\csxdef其内部依赖于\csname ... \endcsname\xdef);

  • 如果命令已经定义,则打印一条错误消息(这用于\ifcsdef执行测试;当然,如果您希望能够重新定义该命令,只需删除测试\ifcsdef\errmessage调用即可);

  • 使用etoolbox\expandonce{...}命令作为 的语法糖\unexpanded\expandafter{...}

\documentclass{article}
\usepackage{environ}
\usepackage{etoolbox}

\NewEnviron{definemycommand}[1]
  {%
    \ifcsdef{#1}
      {\errmessage{%
         Command \expandafter\string\csname#1\endcsname\space already defined}%
      }
      {\csxdef{#1}{\expandonce{\BODY}}}%
  }
  {}

\begin{document}

\newcommand*{\whatever}{foo bar}

\begin{definemycommand}{mycommand}
  \whatever\space here my macro commands
\end{definemycommand}

\show\mycommand                 % ->\whatever \space here my macro commands.
X\mycommand X

% ERROR: Command \mycommand already defined.
% \begin{definemycommand}{mycommand}
%   here my macro commands
% \end{definemycommand}

\end{document}

在此处输入图片描述

的输出\show\mycommand,即:

> \mycommand=macro:
->\whatever \space here my macro commands.

\mycommand证明在定义宏(例如)时,环境主体中使用的宏不会展开。这正是\unexpanded没有 的示例中的 的目的etoolbox,或\expandonce在此示例中。环境主体中给出的此类宏将在\mycommand多次展开时展开(大概是作为排版的一部分,但这实际上取决于您将在何处以及如何使用它)。这通常是一个理想的属性,这就是我以这种方式实现事物的原因(否则,简单的\xdef\csxdef就可以完成工作)。

答案2

使用 的xparse参数b类型来获取环境的主体:

\documentclass{article}
\usepackage{xparse}
\NewDocumentEnvironment{definemycommand}{mb}
  {\gdef#1{#2}}% #1 is the macro name, and #2 is the env body
  {}
\begin{document}

\begin{definemycommand}{\test}
  here my macro coomands
\end{definemycommand}

\texttt{\meaning\test}

\end{document}

在此处输入图片描述

请注意,您必须使用\gdef(或类似的东西),否则环境结束时定义就会丢失。

答案3

我不确定这有什么用。无论如何,你可以这样做。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\tl_new:N \g__definecommand_temp_tl

\NewDocumentEnvironment{definecommand}{mO{0}o+b}
 {
  \IfNoValueTF{#3}
   {
    \tl_gset:Nn \g__definecommand_temp_tl { \newcommand{#1}[#2]{#4} }
   }
   {
    \tl_gset:Nn \g__definecommand_temp_tl { \newcommand{#1}[#2][#3]{#4} }
   }
  \group_insert_after:N \g__definecommand_temp_tl
 }
 {}

\ExplSyntaxOff

\begin{document}

\begin{definecommand}{\fooA}
  this has no arguments
\end{definecommand}

\begin{definecommand}{\fooB}[1]
  this has one argument #1
\end{definecommand}

\begin{definecommand}{\fooC}[2][foo]
  this has one mandatory argument #2 and an optional argument #1
\end{definecommand}

.\fooA.

.\fooB{xyz}.

.\fooC{uvw}.

.\fooC[x]{uvw}.

\end{document}

在此处输入图片描述

相关内容