我惊讶地发现,当我在 LaTex 中创建环境时,会创建一个同名的命令。例如:
\documentclass{minimal}
\newenvironment{foo}{Foo: }{}
\begin{document}
\foo{bar}
\end{document}
产生输出“Foo: bar”,如你所见在此 Overleaf 示例中。除了 Overleaf 之外,它还可以在 Texpad 中使用,因此似乎应用很广泛。
我的第一个问题是:我在哪里可以找到这个文档?它并没有出现在我通常查找的任何地方。
此外,它似乎并不为人所知。例如,当您使用\newcommand
定义命令时,它会作为代码完成中的建议出现。但是当您使用 时,它只会出现在 的代码完成建议中,而不会\newenvironment
出现在 的代码完成建议中(即不是作为命令出现)。\begin{
\
它看起来非常有用:我很乐意使用\align*{...}
而不是\begin{align*}
/\end{align*}
第二个问题:我遗漏了什么吗?这有什么问题吗?
谢谢!
编辑:感谢您周到的详细回答!归根结底,该\newenvironment
命令创建了两个命令:在本例中为\foo
和\endfoo
,一般来说,它们包含您指定的代码。当您执行\begin{foo}
和 时\end{foo}
,它不仅用这些命令包围您的代码,还用 和 包围它\begingroup
,\endgroup
类似于将整个内容包裹在括号中。我已经编辑了上面的背面示例,并 MWE 说明了这如何在用户定义的命令下失败。我还发现这个答案有帮助的。
答案1
抱歉,它不是很有用。试试
\documentclass{article}
\begin{document}
This is some text flush left apart from indentation
\center
This should be centered
\endcenter
and this shouldn't be
\end{document}
您将得到以下输出。您可能会感到惊讶,但您不应该感到惊讶。
会发生什么?当然,执行\newenvironment{foo}{...}{...}
定义\foo
和\endfoo
,因为 TeX 只识别宏。
\begin{foo}
然而,不是\foo
和相同\end{foo}
不是与 相同\endfoo
。事实上,如果我们看一下 的定义\begin
,我们会看到
% latex.ltx, line 7211:
\DeclareRobustCommand*\begin[1]{%
\UseHook{env/#1/before}%
\@ifundefined{#1}%
{\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
{\def\reserved@a{\def\@currenvir{#1}%
\edef\@currenvline{\on@line}%
\@execute@begin@hook{#1}%
\csname #1\endcsname}}%
\@ignorefalse
\begingroup\@endpefalse\reserved@a}
我们意识到\csname #1\endcsname
,在 的情况下,\begin{foo}
会变成\foo
,在处理过程中出现得相当晚。如果我们遵循“假”分支,即在环境确实定义时使用的分支,我们最终会得到
\@ignorefalse\begingroup\@endpefalse
\def\@currenvir{foo}%
\edef\@currenvline{<some line number>}%
\@execute@begin@hook{foo}%
\foo
如果你只是使用\foo
,你就会错过前面的所有代码。理解代码并不重要,但意识到它在那里是至关重要的!
\end{foo}
在处理时也会进行类似的簿记,特别\endgroup
是为了平衡\begingroup
您在上面的代码中看到的先前的内容而发出的。
不管你信不信,正是这\endgroup
一点让大的center
我所展示的例子有所不同。
顺便说一句,amsmath
诸如align
行为甚至不同的环境以及呼叫\align...\endalign
会破坏很多东西!
在某些情况下,\foo
和的\endfoo
使用非常安全,例如根据 定义新环境foo
。但等你成为 LaTeX 编码专家时再考虑这个问题。同时,使用\begin{foo}...\end{foo}
和会很开心。
\usepackage{amsmath}
如果我添加并尝试,这些是我得到的错误
\align a&=b \endalign
他们来了:
Runaway argument?
a&=b \endalign
! Paragraph ended before \document was complete.
<to be read again>
\par
l.7
?
! Missing $ inserted.
<inserted text>
$
l.7
?
! Missing \endgroup inserted.
<inserted text>
\endgroup
l.7
?
! Display math should end with $$.
<to be read again>
\par
l.7
?
没有任何输出。不适合胆小者。
答案2
将我的评论转换成答案。
宏和环境之间存在重要区别:
环境是被群体包围的,而宏则不然。
宏一开始就将其参数标记化,因此宏内部发生的任何事都不会影响参数中标记的 catcode 等。在环境中,输入流中的标记会即时吸收,并受环境过程中发生的变化的影响。
一旦输入流耗尽,环境就允许执行尾随代码(并且需要尾随代码来关闭环境打开的组)。
下面的 MWE 展示了所有这三个差异。
该tokcycle
包允许循环遍历参数或输入流的标记并根据指定的指令对其进行处理。该包提供宏和伪环境形式。所谓“伪环境”,是指需要使用\macro...\endmacro
语法(而不是更熟悉的\begin{envname}...\end{envname}
语法)的环境。
在 MWE 中,我直接排版(而不是存储在令牌寄存器中)tokcycle
已处理的输入。处理如下:任何令牌都将回显到输出,但 cat-7^
令牌除外,它将作为 ed 字符串输出\fbox
。处理完成后,由 定义的值将被\aftertokcycle
排版,这里预设为感叹号!
我使用宏和环境方法来处理以下输入:\chcat This is a ^ test
,其中\chcat
是一个宏,它将的 catcode 更改^
为 的值12
。
项目 1 通过显示在宏退出之后, 的 catcode^
保持在12
,而在环境调用之后,它(由于分组)返回到其先前的值 来证明7
。
第 2 项通过注意到^
宏中只有 被\fbox
标记来证明。这是因为,作为宏参数的一部分, 被^
标记为 catcode 7
,而不管在执行参数的过程中发生了什么变化。在环境替代方案中,未被装箱,因为只有在执行输入流的过程中将^
的 catcode^
更改为之后,它才被标记。12
!
第 3 项通过环境版本中没有尾随代码得到证明。为什么?因为环境形式通过\aftertokcycle
调用所采用的相同宏执行其自己的尾随代码。因此,先前的调用\aftertokcycle
对环境形式没有影响,环境形式使用其尾随代码来重新定义该变量。宏形式不执行任何尾随代码,因此预定义\aftertokcycle
仍然有效。
\documentclass{article}
\usepackage{tokcycle}
\def\chcat{\catcode`^=12}
\begin{document}
\Characterdirective{\tctestifcatnx^#1{\fbox{\string#1}}{#1}}
\Groupdirective{\processtoks{#1}}
\Macrodirective{#1}
\Spacedirective{#1}
\aftertokcycle{!}
Macro form:\\
\begingroup
\tokcyclexpress{\chcat This is a ^ test}
Caret catcode: \number\catcode`^
\endgroup
Environment form:\\
\tokencyclexpress \chcat This is a ^ test\endtokencyclexpress
Caret catcode: \number\catcode`^
\end{document}
对于极客来说:此 MWE 中使用的宏和环境形式tokcyle
都依赖于相同的底层“原始”伪环境。这些接口形式的代码可能有助于阐明为什么宏像宏一样工作,而伪环境像环境一样工作:
宏形式(xpress 接口):
% XPRESS-INTERFACE MACRO FORM
\long\def\tokcyclexpress#1{\tokcycrawxpress#1\endtokcycraw}
伪环境形式(xpress接口):
% XPRESS-INTERFACE ENVIRONMENT FORM
\def\tokencyclexpress{\begingroup\let\endtokencyclexpress\endtokcycraw
\aftertokcycle{\the\cytoks\expandafter\endgroup\expandafter\tcenvscope
\expandafter{\the\cytoks}}\tokcycrawxpress}