(1)测试是否为空的 token 列表作为输入

(1)测试是否为空的 token 列表作为输入

我有一个宏,它包含一些文本值,例如\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}

请注意,与ifmtargWerner 指出的包命令类似,但与 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{}

相关内容