为什么当条件不起作用时,这个抑制命令会起作用?

为什么当条件不起作用时,这个抑制命令会起作用?

我一直在探索在某些条件下抑制环境内容的不同方法。环境的问题在于,由于环境扫描结束标记的方式,许多技巧都不起作用,因此抑制内容通常无法找到抑制的结束。例如:

\begin{document}
\newif\iftest
\testfalse
\newenvironment{testenv}{\iftest}{\fi}
\begin{document}
\begin{testenv}
text!
\end{testenv}
\end{document}

这将返回“incomplete iffalse”,因为它无法找到 \fi,因为它在寻找 \fi 时无法执行 \end{testenv}(因此找不到结尾。这部分我明白了。

我尝试过各种其他方法,但我想远离逐字环境,因为我最终想嵌套它,而嵌套逐字环境是一个巨大的麻烦。

但是后来,我偶然发现了这里的“抑制”命令:选择性地抑制排版输出的生成

因此我编写了以下工作代码:

\documentclass{article}
\usepackage{amsthm}
\usepackage{environ}

\newif\iftest
\testfalse

\NewEnviron{testenv}{\iftest\BODY\else Nope! \fi}
\newcommand{\Test}{}

\makeatletter
\font\dummyft@=dummy \relax
\def\suppress{%
  \begingroup\par
  \parskip\z@
  \offinterlineskip
  \baselineskip=\z@skip
  \lineskip=\z@skip
  \lineskiplimit=\maxdimen
  \dummyft@
  \count@\sixt@@n
  \loop\ifnum\count@ >\z@
    \advance\count@\m@ne
    \textfont\count@\dummyft@
    \scriptfont\count@\dummyft@
    \scriptscriptfont\count@\dummyft@
  \repeat
  \let\selectfont\relax
  \let\mathversion\@gobble
  \let\getanddefine@fonts\@gobbletwo
  \tracinglostchars\z@
  \frenchspacing
  \hbadness\@M}
\def\endsuppress{\par\endgroup}
\makeatother

\newenvironment{testenvtwo}{
\iftest\else\suppress\fi
}{
\iftest\else\endsuppress\fi
}

\begin{document}

Th below should read "Nope"

\begin{testenv}
This shouldn't show!
\end{testenv}

\hrule

Below this should be nothing

\begin{testenvtwo}
This also shouldn't show!
\end{testenvtwo}

\hrule

\testtrue

Below this should be "This should show!"

\begin{testenv}
This should show!
\end{testenv}

\hrule

Below this should be "This also should show!"


\begin{testenvtwo}
This also should show!
\end{testenvtwo}

\hrule

\end{document}

那么,为什么当其他各种方法都失败时,这里的 \suppress 命令却能够正常工作?我真的不明白 \suppress 在实践中是如何工作的,但我认为它只是吞噬它看到的所有内容,直到 \endsuppress 可能?但这似乎应该与 \if \fi 类型结构存在相同的问题。

如果有人能告诉我为什么当 \fi 和来自 etoolbox 等的环境钩子失败时,这个命令会起作用,我将不胜感激。我希望将来能够执行这种命令,所以我正在尝试了解它的工作原理。

答案1

问题是\fi从未见过的。

假设你有这个普通的 TeX 文件

\newif\iftest
\def\blurb{\fi}

\testtrue

\iftest
Yes
\blurb

\testfalse
No
\blurb

\bye

如果\iftest返回 true,\blurb则进行扩展,这样 TeX 就能够看到\fi匹配的\iftest

什么时候\iftest返回 false 时,TeX 会跳过 true 测试无扩展,因此它将处于\bye尚未看到匹配的状态\fi

您的代码也出现了同样的情况。

\documentclass{article}
\begin{document}
\newif\iftest
\testfalse
\newenvironment{testenv}{\iftest}{\fi}
\begin{document}
\begin{testenv}
text!
\end{testenv}
\end{document}

\begin{testenv}执行时,TeX 会看到\iftest,它返回 false,因此它将跳过标记,直到看到\else或 标记\fi。TeX 找不到任何标记,因为扩展在此跳过标记阶段执行。跳过将到达文件末尾,除非出现一些明确的标记\else or\fi` 恰好被扫描。显式是指不隐藏在宏中。

没有安全的方法来埋入\fi环境\end的一部分;只有条件返回真时,这种方法才会起作用。

它是如何\suppress工作的?它只是选择一种没有任何字符的字体,并重新定义字体更改命令\selectfont以不执行任何操作;数学字体也设置为无。但\rule{1cm}{1cm}在环境中尝试,你会看到打印出一些东西。当然还有\rule可以禁用。

条件没有问题,因为 TeX 会\iftest...\fi在开始和结束部分看到完整。

答案2

如果您想要一个在条件为假时被抑制的环境,请使用environ包来获取整个环境内容,并且仅在条件为真时显示它们。

\documentclass{article} 

\newif\iftest 
\testfalse

\usepackage{environ} 
\NewEnviron{test}{\iftest\BODY\fi}

\begin{document} 
\begin{test}
    Should not appear
\end{test} 

\testtrue  
\begin{test}
    Should appear
\end{test} 
\end{document}

相关内容