根据其他环境来定义环境:正确的方法是什么?

根据其他环境来定义环境:正确的方法是什么?

假设我想定义一个新环境,它是现有环境的变体。例如,我寻求一个与现有环境italicquote行为相同quote但内容以斜体显示的环境。LaTeX 伴侣是按照在正文中使用的方式来编写内部环境,即

\newenvironment{italicquote}{%
  \begin{quote}%
  \itshape
}{%
  \end{quote}%
}

然而,在回答定义我自己的描述环境Martin Scharrer 主张将内部环境写成简单的形式,即将我的例子转化为

\newenvironment{italicquote}{%
  \quote
  \itshape
}{%
  \endquote
}

他的理由是:

内部环境以 [...] 的纯格式写入,以避免在\end{italicquote}缺少 [ ] 时混淆错误消息。在这种情况下,最后一个\begin将是内部宏的名称,其名称将打印在错误消息中,而不是源文件中写入的名称。对于您自己的小环境来说,这不是问题,但如果它们被其他人使用,则很重要。

第二种定义“派生”环境的方式是否无一例外地更受青睐?如果是,那么为什么LaTeX 伴侣使用第一种方式?如果不是,那么在我的示例环境中,在什么情况下应该更喜欢写\begin{quote}... ?\end{quote}

答案1

我被告知要对内部环境使用“普通形式”的原因是,正如问题中已经引用的那样,如果正常\begin\end使用正常的/形式并且最后一个\end{<outer env>}缺失或放错位置,则错误消息将包含最后一个的名称 \begin{<env>}。用户可能不知道外部环境在内部使用此环境,因此可能会感到困惑。由于它可以是多个使用环境的一部分,因此错误不会提供太多有关查找位置的信息(除了行号,如果您坚持每行一个,那么行号可能就是您所需要的全部信息\begin)。


\begin让我们看看和的定义,\end看看这两种形式之间的确切区别是什么:

\def\begin#1{%
  \@ifundefined{#1}%
    {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
    {\def\reserved@a{\def\@currenvir{#1}%
     \edef\@currenvline{\on@line}%
     \csname #1\endcsname}}%
  \@ignorefalse
  \begingroup\@endpefalse\reserved@a}

因此\begin检查#1(环境名称)是否存在于宏中,如果不存在则报告错误。否则将保存当前列表和名称。后者为\@currenvir。这是在用打开的组中完成的\begingroup@ignore开关用于忽略后面的空格,而开关@endpe用于“在段落制作环境之后立即抑制文本中的段落缩进”(来源2e)。

\def\end#1{%
  \csname end#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}

\end执行\end<envname>。然后检查使用\@checkend的名称是否等于上次打开的\begin。如果两者不相等,则打印错误消息。然后执行代码\@doendpe以抑制段落缩进(如果已启用)并关闭该组。如果已启用,则可能会忽略空格。


让我们看看区别:如上面的代码描述所示,如果使用普通的 LaTeX 格式,还会做以下事情:

  1. 检查其存在性。
  2. 已添加群组。
  3. 环境名称已保存。
  4. 环境开始的行号被保存。
  5. 之后的空格可以被忽略。
  6. 可以避免段落缩进。

我们的内部环境需要这些东西吗?:

  1. 不是,应该知道内部环境是否存在。
  2. 外部环境已添加一个组,并且几乎从不需要一个额外的组。一个例外是逐字以及其他特殊环境,如果不采取额外的预防措施,这些环境无论如何都无法嵌套。可能有一些非逐字环境需要为其自身设置一个内部组,但这些环境不应依赖于\begin/添加的组\end,而应明确添加。无论如何,如果需要,可以手动添加该组。
  3. 这是应该直接避免的事情。
  4. 已被外界环境所拯救。
  5. 可以通过外部环境来完成,并且因为\end{xxx}以 结尾}所以它不需要删除空格,所以这是必需的。但是普通形式\endxxx确实需要删除空格,因此不需要删除空格。\ignorespaces如果有人坚持,可以添加显式的。
  6. 这一点是我在写这个答案时才发现的最重要的一点:段落是否应该缩进。这似乎在某些环境的开始代码中设置为 true,并在执行后在内部重新设置为 false \end。因此,如果使用普通版本,它将移动到外部,\end这可能是也可能不是正确的事情。我建议在最后手动将开关设置@endpe为正确的值以避免出现问题。

结论:

只要处理好预期的段落缩进,使用普通形式作为内部环境应该没有问题。它们的优点是可以生成有意义的错误消息,而且速度稍快,不会生成(通常)不必要的子组。特殊的内部环境可能需要特别小心。

相关内容