据我了解,当我指定
\newenvironment{env}{
start
}{
end
}
LaTeX 实际上做的是定义两个宏
\env -> start
\endenv -> end
以便
\begin{env}
middle
\end{env}
解析为类似
{
\env
middle
\endenv
}
- 我的看法是否正确且完整?
- 还有其他事吗
\newenvionment
,\begin
要做\end
什么? \newenvironment
我是否可以不通过定义\env
和来创建环境\endenv
?是否有可能从中受益的情况?- 不使用
\env
and是否安全?例如,避免分组。\endenv
\begin
\end
- 有何
xparse
不同\NewDocumentEnvironment
?
许多问题,都由一个请求相关:请解释环境和相关命令如何工作。
答案1
LaTe2e 环境实现的基础知识涵盖LaTeX 如何实现环境?。在xparse
,该方法稍微复杂一些,以便允许#1
,ETC。在环境代码的末尾有一个动态定义。但是,对性能的影响很小。在 LaTeX2e 之上,仍然需要进行设置\foo
,\endfoo
因为这就是\begin
我们\end
想要的。但是,长期愿景是为环境代码提供专用的命名空间,xparse
因此为此目的包括第二层宏。
答案2
仅部分答案:
环境
\newenvironment
确实定义了\env
和\endenv
(如果用作env
参数)但是
\env...\endenv
不是组安全的,请参见下面示例中长度变量的设置。无法定义
\newcommand{\otherenv}
和\newcommand{\otherendenv}
,因为这会导致错误:
!LaTeX 错误:命令 \endotherenv 已定义。或名称 \end... 非法,请参阅手册第 192 页。
See the LaTeX manual or LaTeX Companion for explanation. Type H <return> for immediate help.
\end...
大约一年前,我曾问过有关宏的类似问题:\end.... 宏名称在 LaTeX2e 中保留吗?
但是,可以说\def\otherenv
和\def\endotherenv
。事实上,LaTeX 核心或包中定义了多少个 LaTeX2e 环境——例如,enumerate
是\def\enumerate
和\def\endenumerate
而不是使用\newenvironment{enumerate}
\documentclass{article}
\newenvironment{env}{}{}
\newlength{\mylength}
\setlength{\mylength}{10pt}
\begin{document}
\begin{env}
\addtolength{\mylength}{20pt}
\end{env}
Result after: \the\mylength $\longrightarrow$ safe!
\env
\addtolength{\mylength}{20pt}
\endenv
Result after: \the\mylength $\longrightarrow$ not safe!
% Now some grouping:
{
\env
\addtolength{\mylength}{20pt}
\endenv
}
Result after: \the\mylength $\longrightarrow$ safe again!
\end{document}
此外,用 定义的环境\newenvironment
具有“自我意识”(好吧 ;-))——它知道当前环境名称,但只有在\begin{env}...\end{env}
使用 时才知道,而不是用\env...\endenv
或{\env...\endenv}
看第二个例子:
\documentclass{article}
\makeatletter
\newcommand{\ShowEnvName}{%
Current environment: \@currenvir
}
\makeatother
\newenvironment{env}{}{}
\begin{document}
\begin{env}
\ShowEnvName : Should be \texttt{env}
\end{env}
\env
\ShowEnvName : Presumed to be \texttt{env}, but is \texttt{document}
\endenv
{
\env
\ShowEnvName : Presumed to be \texttt{env}, but still is \texttt{document}
\endenv
}
\env
{
\ShowEnvName : Presumed to be \texttt{env}, but still is \texttt{document}
}
\endenv
\end{document}
一旦没有\begin...\end
配对,它就会显示外部环境名称 - 这就是\begin...\end
设置\@currenvir
宏所做的 -->。
来自(或参见 texdoc source2e)和latex.ltx
的定义:\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}
\def\end#1{%
\csname end#1\endcsname\@checkend{#1}%
\expandafter\endgroup\if@endpe\@doendpe\fi
\if@ignore\@ignorefalse\ignorespaces\fi}
\def\@checkend#1{\def\reserved@a{#1}\ifx
\reserved@a\@currenvir \else\@badend{#1}\fi}
\begin
首先检查环境是否完全定义,并在错误分支中给出错误。如果成功,则将变量@currenvir
设置为环境,\csname #1\endcsname
即\env
调用并\begingroup
启动。
\end
检查正确的环境是否此时关闭,即如果之后尚未打开\begin{env}...\end{otherenv}\end{env}
则会出错。otherenv
env