以 \begin 和 \end 为条件

以 \begin 和 \end 为条件

MWE 宏的条件结构允许交替打印两个文本字符串“ true”和“ false”。因此,您可以打印类似“ false true false true false true”的内容,而无需任何选项即可调用相同的宏六次。

但是如果打印的字符串构成了环境(即:\begin{...}\end{...}),这只会在第一次起作用,就像在 MWE 中一样。第二次 \tin .... \tinpdflatex表示\begin{document}结束于\end{...}

\documentclass{article}
\newif\iftiny
\def\tin{\iftiny
\tinyfalse \end{tiny}
\else
\tinytrue \begin{tiny} 
\fi}
\begin{document}
 normal size 
\tin tiny size \tin normal size
% uncomment the next line to see the problem 
% \tin tiny size \tin normal size   
\end{document}
  • \begin{tiny}当该宏被调用四次时,第二次会发生什么?
  • 这段代码为什么是错误的?
  • 如何修复这个问题?

答案1

每条\begin命令都对应着发出的\begingroup一个命令。\endgroup\end

\tinyfalse或等作业\tinytrue只限于其所在组。如果您希望作业超越其所在组,则可以执行\global\tinytrue和。\global\tinyfalse

让我们看看你的代码发生了什么。

\tin tiny size \tin normal size

变成

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

由于条件最初为假,因此跳过真分支,并且

\tinytrue\begin{tiny}\fi tiny size \tin normal size

剩余。执行分配后,tiny环境启动,\begingrouptiny打印大小(\fi由于正在工作,消失)。现在请记住,我们在一个组中;当\tin找到时,它会展开,我们面临的是

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi normal size

现在\iftiny遵循真正的分支,结果标记列表是

\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi normal size

执行赋值后,\end{tiny}将执行其,\endgroup这将撤消所做的赋值\tinyfalse,因此\iftiny仍为真。该\else...\fi部分消失并被normal size打印出来。

如果现在再次执行输入

\tin tiny size \tin normal size

你从返回 true 开始\iftiny!所以

\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

跟随真正的分支,给出

\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi tiny size \tin normal size

还有一个\end{tiny}不属于那里的东西。

答案2

除了对 egreg 的解释之外,这里还有另一种定义条件的方法:

\documentclass{article}
\let\iftiny\iffalse
\def\tinytrue{\global\let\iftiny\iftrue}
\def\tinyfalse{\global\let\iftiny\iffalse}
\def\tin{\iftiny\tinyfalse\end{tiny}\else\tinytrue\begin{tiny}\fi}
\begin{document}
 normal size 
\tin tiny size \tin normal size
 uncomment the next line to see the problem 
 \tin tiny size \tin normal size   
\end{document}

楼主说这个解决方案不太直观。所以我觉得\newif有必要稍微解释一下。

该命令\newif在 LaTeX 内核中定义如下

\def\newif#1{%
  \count@\escapechar \escapechar\m@ne
    \let#1\iffalse
    \@if#1\iftrue
    \@if#1\iffalse
  \escapechar\count@}

这个非常巧妙的定义做了三件事。首先,它定义了一个等于的新命令\iffalse\let#1\iffalse这等于上面的例子。

接下来的两行调用\@if具有以下定义的宏:

\def\@if#1#2{%
  \expandafter\def\csname\expandafter\@gobbletwo\string#1%
                    \expandafter\@gobbletwo\string#2\endcsname
                       {\let#1#2}}

简而言之,它吞噬输入字符串的前两个标记一和二,例如从\iftiny您获得tiny和从\iffalse您获得false。在下一步中,您将获得定义:\def\tinyfalse{\let\iftiny\iffalse}。上面的解决方案几乎相同,但它添加了一个\global赋值。

相关内容