如何检查条件,如果\commandtwo
在 tex 文件中出现,\commandone
\if
条件应该是过程,否则\else
条件应该是过程?如何制定条件?
注意:\commandtwo{XXX}
在 之后的 tex 文件中可能会出现或不会出现,但和的\begin{document}
定义在序言中。\def\commandone#1{#1}
\def\commandtwo#1{#1}
\def\commandthree#1{#1}
MWE文件如下:
\documentclass{book}
\makeatletter
%\commandtwo present in the file \if condition should be process if not presented in the file \else condition should be process
\def\commandone#1{\ifx\@ScndArg\@empty{\Huge#1}\else{\tiny#1}\fi}
\def\commandtwo#1{\def\@ScndArg{#1}#1}
\def\commandthree#1{#1}
\makeatother
\begin{document}
\commandone{AAA}
\commandtwo{BBB}
\commandthree{CCC}
\end{document}
答案1
由于\commandtwo
可能出现后 \commandone
,您需要考虑使用 来.aux
存储将在二次编译中使用的内容。下面\commandtwo
写入将在下一次编译时读取的\gdef\commandtwopresent{}
内容.aux
。即使它被定义为空,它也可以用于通过\ifcsname
...进行条件处理\endcsname
。
\documentclass{article}
\makeatletter
%\commandtwo present in the file \if condition should be process if not presented in the file \else condition should be process
\def\commandone#1{\ifcsname commandtwopresent\endcsname {\Huge#1}\else{\tiny#1}\fi}
\def\commandtwo#1{%
\immediate\write\@auxout{\gdef\string\commandtwopresent{}}%
#1}
\def\commandthree#1{#1}
\makeatother
\begin{document}
\commandone{AAA}
\commandtwo{BBB}
\commandthree{CCC}
\end{document}
答案2
Werner 建议通过 .aux 文件定义宏,定义的宏指示是否在之前的 LaTeX 运行中\commandtwo
执行过。
根据这个建议,我提供了一种变体,其中写一个交叉引用标签,其结果是“真”或“假”,并且可以在\csname..\endcsname
产生\iftrue
或的表达式中使用\iffalse
。
这种变体的优点是,如果由于某些内容发生变化而必须重新编译,则会通过控制台和 .log 文件通知您,因为更改伴随着所述交叉引用标签的更改,而交叉引用标签的更改由 LaTeX 内核跟踪。
这种变体的一个缺点是,需要额外的包,即包尽头,需要在正确的时间点挂接以写入所述交叉引用标签。
\documentclass{book}
\usepackage{atveryend}
%\usepackage{hyperref}
\makeatletter
\AfterLastShipout{%
\immediate\write\@auxout{\string\newlabel{CommandTwoUsed}{\CommandTwoUsed}}%
}%
\newcommand\CommandTwoUsed{false}
\AtBeginDocument{%
\expandafter\newcommand
\expandafter\CheckWhetherCommandTwoUsed
\expandafter{%
\csname if\@ifundefined{r@CommandTwoUsed}{false}{\r@CommandTwoUsed}\endcsname
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
}%
\newcommand\commandtwo[1]{\gdef\CommandTwoUsed{true}#1}
\newcommand\commandone[1]{\CheckWhetherCommandTwoUsed{{\Huge#1}}{{\tiny#1}}}
\newcommand\commandthree[1]{#1}
\makeatother
\begin{document}
\commandone{AAA}
\commandtwo{BBB}
\commandthree{CCC}
\end{document}
答案3
短语“\commandtwo
存在于文件中”中的“存在”到底是什么意思?
\input
假设有问题的 .tex-input-file(或通过或处理的其他文件\include
,属于有问题的文档?)包含
\verb|\commandtwo...|
和/或
% This is a comment containing \commandtwo
。
\commandtwo
在这种情况下,存在于文件中的条件会得到满足吗?
如果您只想知道是否\commandtwo
已经执行/尚未执行,同时假设\@ScndArg
除了执行之外没有其他定义方法\commandtwo
,那么您可以检查是否\@ScndArg
已定义/未定义。
沃纳 (Werner) 已经在他的回答中展示了如何在\ifcsname..\endcsname
ε-TeX 扩展可用的情况下做到这一点。
为了好玩,您可以通过检查\meaning
该标记的 是否包含短语“未定义”来测试宏参数是否具有第一个标记(即未定义的控制序列)。这样就不需要依赖任何 TeX 扩展的可用性:
\errorcontextlines=10000
\documentclass{article}
\makeatletter
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@CheckWhetherNull,
%% \UD@stopromannumeral
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}%
{\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Check whether brace-balanced argument has a first token which is an
%% undefined control sequence.
%% (Only with undefined control sequences the \meaning has the leading phrase
%% "undefined"; besides this \meaning never delivers no tokens at all)
%%.............................................................................
%% \CheckWhetherLeadingUndefined{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked> has a 1st token
%% which is undefined>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked> does not have a 1st
%% token which is undefined>}%
\begingroup
\def\CheckWhetherLeadingUndefined#1{%
\endgroup
\newcommand\CheckWhetherLeadingUndefined[1]{%
\romannumeral\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string##1X}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
% Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
% and thus do not disturb when the test is carried out within \halign/\valign:
\expandafter\UD@firstoftwo\expandafter{%
\expandafter\expandafter\expandafter\UD@stopromannumeral
\romannumeral\expandafter\UD@secondoftwo
\string{\expandafter\UD@CheckWhetherLeadingUndefinedB\expandafter.\meaning##1X#1}{}%
}{}%
}%
}%
\@ifdefinable\UD@CheckWhetherLeadingUndefinedB{%
\long\def\UD@CheckWhetherLeadingUndefinedB##1#1{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}##1}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\expandafter\expandafter}%
\expandafter\UD@secondoftwo\expandafter{\string}%
}%
}%
}%
\escapechar=-1\relax
\expandafter\CheckWhetherLeadingUndefined\expandafter{\string\undefined}%
\makeatother
\begin{document}
\medskip\hrule\medskip
The sequence \verb|abc|
\CheckWhetherLeadingUndefined{abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|\TeX abc|
\CheckWhetherLeadingUndefined{\TeX abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The empty sequence
\CheckWhetherLeadingUndefined{}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The blank sequence \verb*| |
\CheckWhetherLeadingUndefined{ }{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|\else|
\CheckWhetherLeadingUndefined{\else}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|{\UnDefIneD} abc|
\CheckWhetherLeadingUndefined{{\UnDefIneD} abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|{}\UnDefIneD abc|
\CheckWhetherLeadingUndefined{{}\UnDefIneD abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb*| \UnDefIneD abc|
\CheckWhetherLeadingUndefined{ \UnDefIneD abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|\UnDefIneD \fi \csname abc|
\CheckWhetherLeadingUndefined{\UnDefIneD \fi \csname abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
The sequence \verb|\UnDefIneD abc|
\CheckWhetherLeadingUndefined{\UnDefIneD abc}{does have}{does not have}
a leading token which is an undefined control sequence.
\medskip\hrule\medskip
\end{document}
另一种方法是,在 verbatim-catcode-régime 下重新读取整个相关输入文件,通过分隔参数检查是否\commandtwo
存在该短语。但是,如果注释包含该短语,则可以避免这种情况。如果输入文件 A 和输入文件 B 都属于同一文档,并且输入文件 A 在处理输入文件 B 之前被处理,则在输入文件 B 中,这也可以通过输入文件 A 包含\let\foobar=\commandtwo
和输入文件 B 包含来避免\foobar
这种情况,而不是\commandtwo
。
因此,我不会详细阐述这一点,除非您发表评论表明尽管这种方法存在缺点,但您仍对其感兴趣。