将 \begin{foo}...\end{foo} 缩写为 \bfoo ... \efoo 是否安全

将 \begin{foo}...\end{foo} 缩写为 \bfoo ... \efoo 是否安全

我可以安全地这样做吗:

\newcommand\bfoo{\begin{foo}}
\newcommand\efoo{\end{foo}}

哪里foo有标准的 LaTeX 环境?可能verbatim环境有问题,但其他环境也有问题?这样就可以写

\bfoo
inside the foo environment
\efoo

而不是更长的

\begin{foo}
inside the foo environment
\end{foo}

我希望得到一个技术性声明,而不是“我不会这样做,因为它不可读”。事实上,我只是想知道它的含义,我不会这样做,因为我认为它不太可读。

答案1

正如您所说,任何基于查找\end{foo}构造的操作都会失败。这包括任何逐字类操作,例如包括beamerframe环境,也包括一些 AMS 数学环境,例如align

第二个问题是空间跳跃,因为

\begin{foo}
inside the foo environment
\end{foo}

inside版本号前面有一个空格\bfoo。您可能觉得这不是什么坏事,但它改变了界面的工作方式。(注意:某些环境故意\ignorespaces在开始时加上,但这并不适用,例如lrbox。)

答案2

在很多情况下可以使用这种快捷方式,但总的来说并不安全。

尸体收集者

突出的例子是包amsmath。它具有这样的特点:在其显示的方程环境(收集、对齐等)中,方程编号的处理得到了改进。数字向下移动而不是与方程冲突。但为此amsmath需要知道方程的宽度。因此,它定义了在参数文本中\collect@body查找的宏\end,以挖掘内部嵌套环境以找到\end关闭环境的正确方法。

\def\collect@@body#1\end#2{...}% the relevant internal

因此\end必须在同一级别可见,并且不能隐藏在宏、别名或组中。但是该\begin部分不受影响,因此可以用于定义:

\newcommand{\bfoo}{}
\def\bfoo#1\efoo{\begin{foo}#1\end{foo}}

现在,\end{foo}可以看到 中的代码\begin{foo}。这种方法的缺点是正确嵌套存在问题:

\bfoo ... \bfoo ... \efoo ... \efoo

第一个\bfoo会找到第一个\efoo,而不是正确的最后一个\efoo。解决方法:

\bfoo ... {\bfoo ... \efoo} ... \efoo

environ使得该方法amsmath可以作为独立包使用。

逐字

使用已更改的 catcode 处理其主体的环境,主要是因为它们不希望主体中的宏和命令被执行。在逐字记录的情况下,它们应该不加改变地打印。但这也会影响结束宏,它被读取为字符序列,并且不会被构建和调用为宏标记。这包括\end{...}verbatim环境通过查找字符序列\end{v、 …… 作为结束标记来解决这个问题。因此\efoo不会检测到类似的东西。

该包verbatim使用略有不同的方法,它逐行扫描并收集标记,直到找到\end其中包含匹配的环境名称的字符串。

相关内容