![条件 \if \fi 使用钩子 \AtBeginDocument 和 \AtEndDocument](https://linux22.com/image/339605/%E6%9D%A1%E4%BB%B6%20%5Cif%20%5Cfi%20%E4%BD%BF%E7%94%A8%E9%92%A9%E5%AD%90%20%5CAtBeginDocument%20%E5%92%8C%20%5CAtEndDocument.png)
我想知道在 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}