我有一个宏,它包含一些文本值,例如\macro{some text}
。如果它为空,我希望文档中不显示任何内容,但它包含任何类型的内容,这些内容会产生显示在文档中的文本,我希望出现一条消息,“文本:一些文本”。
\macro{}
将被视为空。\def\somedata{}
,\macro{\somedata}
将被视为空。\macro{0}
将被认为不为空。
我曾尝试制作一个 TeX 条件来检查值是否不为空,但都不起作用,例如:
\ifx #1 {}
\else
Text: #1
\fi
\ifx#1{}
\else
Text: #1
\fi
\ifx #1 \nil
\else
Text: #1
\fi
\ifx#1!=""
\else
Text: #1
\fi
在纯 TeX 中创建条件并检查值是否为空的正确语法是什么?
答案1
(1)测试是否为空的 token 列表作为输入
你可以试试
\def\temp{#1}\ifx\temp\empty
<EMPTY>%
\else
<NON EMPTY>%
\fi
如果你知道一个标记,比如说\hfuzz
,不会出现在中#1
,那么
\ifx\hfuzz#1\hfuzz
<EMPTY>%
\else
<NON EMPTY>%
\fi
与之前的测试不同,这项测试是可扩展的。
最安全的测试使用 e-TeX:
\if\relax\detokenize{#1}\relax
<EMPTY>%
\else
<NON EMPTY>%
\fi
使用最后一个应该没有问题,但请注意它不适用于“Knuth TeX”。
评论
您还应该知道,\ifx
比较其后的两个标记,并且没有=
符号。同样,\if
比较其后的两个标记,但要先进行完全扩展。
那么,最后一个测试是如何进行的?将\detokenize{#1}
参数转换为类别代码为 12 的字符序列,其中没有一个与\if
等价\relax
。因此,对于空,#1
测试将\relax
与进行比较\relax
,因此返回 True;对于#1
非空,例如abc
,代码将是
\if\relax abc\relax<EMPTY>\else<NOT EMPTY>\fi
\relax
和之间的比较a
返回 False,因此只<NOT EMPTY>
保留代码。
(2)测试无打印输出
为了测试没有打印输出,您不能进行可扩展的测试:
\setbox0=\hbox{#1\unskip}\ifdim\wd0=0pt
<EMPTY>%
\else
<NOT EMPTY>%
\fi
这假设#1
不包含垂直材料,例如。如果还应考虑“空间输出”,则\vfill
删除。但是,当调用时,这可能会出错;这主要取决于您期望在参数中出现什么以应对极限情况。\unskip
\mymacro{\hskip1pt\hskip1pt}
如果使用 e-TeX,则可以定义一个\foreverunspace
宏来删除所有尾随空格(假设没有出现任何内容):
\def\foreverunspace{%
\ifnum\lastnodetype=11
\unskip\foreverunspace
\else
\ifnum\lastnodetype=12
\unkern\foreverunspace
\else
\ifnum\lastnodetype=13
\unpenalty\foreverunspace
\fi
\fi
\fi
}
因此测试可以
\setbox0=\hbox{#1\foreverunspace}\ifdim\wd0=0pt
<EMPTY>%
\else
<NOT EMPTY>%
\fi
这样可以消除任何尾随的粘连、字距和惩罚组合。
答案2
这etoolbox
软件包提供\ifdefempty
(以及它的\ifcsempty
控制序列名称的同类):
\documentclass{article}
\usepackage{etoolbox}
\def\mymacroA{}
\def\mymacroB{ }
\def\mymacroC{E}
\def\mymacroD{ E }
\begin{document}
\ifdefempty{\mymacroA}{YES}{NO}\par
\ifdefempty{\mymacroB}{YES}{NO}\par
\ifdefempty{\mymacroC}{YES}{NO}\par
\ifdefempty{\mymacroD}{YES}{NO}
\end{document}
请注意,与ifmtarg
Werner 指出的包命令类似,但与 Caramdir 的\ifx
测试不同,\ifdefempty
对于由至少一个空格而没有其他内容的宏参数,将扩展为“true”。
答案3
使用ifmtarg
包裹:
\documentclass{article}
\usepackage{ifmtarg}% http://ctan.org/pkg/ifmtarg
\makeatletter
\newcommand{\isempty}[1]{%
\@ifmtarg{#1}{YES}{NO}}
\newcommand{\isnotempty}[1]{%
\@ifnotmtarg{#1}{YES}}
\makeatother
\begin{document}
\verb|\isempty{} |: \isempty{} \par
\verb|\isempty{ } |: \isempty{ } \par
\verb|\isempty{E} |: \isempty{E} \par
\verb|\isempty{ E }|: \isempty{ E }
\bigskip
\verb|\isnotempty{} |: \isnotempty{} \par
\verb|\isnotempty{ } |: \isnotempty{ } \par
\verb|\isnotempty{E} |: \isnotempty{E} \par
\verb|\isnotempty{ E }|: \isnotempty{ E }
\end{document}
它定义\@ifmtarg{<stuff>}{<true>}{<false>}
和\@ifnotmtarg{<stuff>}{<true>}
。
答案4
一种方法是这样做:
\makeatletter
\def\test#1{%
\def\tmp{#1}%
\ifx\tmp\@empty%
Nothing here!%
\else%
You passed: \texttt{#1}.%
\fi%
}
\makeatother
这里\@empty
由 LaTeX 定义为\def\@empty{}
。