条件 \if \fi 使用钩子 \AtBeginDocument 和 \AtEndDocument

条件 \if \fi 使用钩子 \AtBeginDocument 和 \AtEndDocument

我想知道在 LaTeX 中是否有办法从序言开始在整个文档中创建条件?类似于此示例(显然不起作用):

\documentclass{article}

\AtBeginDocument
{
  \if 1
}
\AtEndDocument
{
  \fi
}

\begin{document}
My test 1
\fi\if 2
My test 2
\fi\if 3
My test 3
\end{document}

答案1

问题中的方法存在问题,即 TeX 中条件句的解析规则。如果 TeX 扩展一个\if...表达式,它会将其求值为\iftrue\iffalse。如果为真,则它会继续扩展,直到找到\else。然后 TeX 进入跳过模式,直到找到结尾的\fi。如果\if...求值为\iffalse,则 TeX 会跳过所有内容,直到下一个\else\fi

在跳过模式下,TeX 检查每个标记,看它是否具有条件的含义:\else以及\fi内部\if...构造。关键点在于宏不是展开。如果\fi隐藏在宏内,则跳过该宏,并且 TeX 将永远看不到\fi其内部定义。

这恰恰发生在

\AtEndDocument{\fi}

那么 TeX 将不会看到\fi

\iffalse
\end{document}

并将继续读下去\end{document}

解决方法

以下示例使用包environ来捕获环境的内容document。限制是,不支持同一文件(包含的文件也可以)中文档内的类别更改。

\documentclass{article}

\usepackage{environ}

% Patches to support arguments with conditionals out of order
\makeatletter
\long\def\Collect@@Body#1\end#2{%
  \edef\begin@stack{%
    \Push@Begins#1\begin\end\expandafter\@gobble\begin@stack}%
  \ifx\@empty\begin@stack
    \endgroup
    \@checkend{#2}%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \Addto@Envbody{#1}%
  }{%
    \Addto@Envbody{#1\end{#2}}%
  }%
  \process@envbody
}
\long\def\Push@Begins#1\begin#2{%
  \expandafter\ifx\expandafter\end\@car#2\@empty\@nil
  \else
    b\expandafter\Push@Begins
  \fi
}
\makeatother

\let\OrgDocument\document
\let\endOrgDocument\enddocument
\let\document\relax
\let\enddocument\relax
\NewEnviron{document}{%
  \global\let\document\OrgDocument
  \global\let\enddocument\endOrgDocument
  \expandafter\endgroup
  \expandafter\WrapDocument\expandafter{\BODY}%
}
\newcommand{\WrapDocument}[1]{%
  \begin{document}%
    \iffalse
    #1%
    \fi
  \end{document}%
}

\begin{document}
My test 1
\fi\iftrue
\begin{center}
My test 2
\end{center}
\fi\iffalse
My test 3
\end{document}

结果

相关内容