了解 etoolbox \ifdefempty 和 \ifdefvoid

了解 etoolbox \ifdefempty 和 \ifdefvoid

我正在尝试理解etoolbox \ifdefempty\ifdefvoid宏。文档说\ifdefempty

如果控制序列已定义并且是替换文本为空的无参数宏,则扩展为 true,否则扩展为 false。

相似地\ifdefvoid

如果控制序列未定义,则扩展为 true;如果是含义为 的宏\relax,或替换文本为空的无参数宏,则扩展为 false。

根据这些描述,我认为\def\myempty{}\def\myrelax{\relax}\def\myemptyempty{\myempty}都既是“空”又是“无效”,但\def\myempty{}是唯一一个既是“空”又是“无效”的。我遗漏了什么?

\documentclass{minimal}
\usepackage{etoolbox}

\begin{document}

\def\myempty{}
\def\myrelax{\relax}
\def\myemptyempty{\myempty}


\ifdefempty{\myempty}{Empty}{Not empty}

\ifdefempty{\myrelax}{Empty}{Not empty}

\ifdefempty{\myemptyempty}{Empty}{Not empty}

\ifdefvoid{\myempty}{Void}{Not void}

\ifdefvoid{\myrelax}{Void}{Not void}

\ifdefvoid{\myemptyempty}{Void}{Not void}

\end{document}

答案1

假设通过了(已定义且无参数)\<cs>的前两个测试,则在内执行下一个测试 - 替换文本是否为空。此测试检查的是否为“空白”:\ifdefempty\etb@ifdefempty\meaning\<cs>

\def\etb@ifdefempty#1{%
  \expandafter\expandafter
  \expandafter\ifblank
  \expandafter\expandafter
  \expandafter{%
  \expandafter\strip@prefix\meaning#1}}

这里的“空白”是根据 的 进行检查的。\strip@prefix这只是从 的输出中删除了 部分(因此更改为)。因此,在\meaning#1macro:->\meaningmacro:->\relax\relax

  • \myempty,检查\ifblank{}哪个为真。
  • \myrelax,检查结果\ifblank{\relax}为假。
  • \myemptyempty,支票是\ifblank{\myempty},这是错误的。

以下更新版本\ifdefempty实际上向您展示了所执行的比较:

在此处输入图片描述

\makeatletter
\renewcommand{\ifdefempty}[1]{
  {\ttfamily\expandafter\strip@prefix\meaning#1\quad}%
  \ifundef{#1}
    {\@secondoftwo}
    {\ifdefmacro{#1}
       {\ifdefparam{#1}
      {\@secondoftwo}
      {\etb@ifdefempty{#1}}}
       {\@secondoftwo}}}
\makeatother           

的内部工作\ifdefvoid原理类似,因为它使用相同的最内层函数进行测试,即\etb@ifdefempty。以下更新版本\ifdefvoid突出显示了测试针对的内容:

在此处输入图片描述

\makeatletter
\renewcommand{\ifdefvoid}[1]{%
  {\ttfamily\expandafter\strip@prefix\meaning#1\quad}%
  \ifundef{#1}
    {\@firstoftwo}
    {\ifdefmacro{#1}
       {\ifdefparam{#1}
      {\@secondoftwo}
      {\etb@ifdefempty{#1}}}
       {\@secondoftwo}}}
\makeatother

答案2

宏是带有替换文本的无参数宏。您可以获得具有以下\def\myrelax{\relax}含义的命令序列:\myrelax\relax\relax\let

\let\myrelax\relax

还定义了一个非空的\def\myemptyempty{\myempty}无参数宏,其替换文本为。首先展开替换文本:\myemptyempty\myemptyempty\edef

\edef\myemptyempty{\myempty}

概括:

\ifdefempty抓住案例:

  • \myempty\def\myempty{}

以及\ifdefvoid案例:

  • \UnDeFiNeDCoMmAnD
  • \myrelax\let\myrelax\relax
  • \myempty\def\myempty{}

答案3

我们不必深究其内部原理,只需分析记录的行为即可。

\ifdefempty:如果控制序列已定义并且是替换文本为空的无参数宏,则扩展为 true,否则扩展为 false。

这意味着\ifdefempty{\cs}测试是否\cs是一个宏(即可扩展的非原始控制序列),不带参数,并且其第一级扩展为空。也就是说,它应该通过以下方式创建

\def\cs{}
\edef\cs{<stuff expanding to empty text>}
\let\cs<control sequence for which \ifdefempty{} is true>

\ifdefvoid:如果控制序列未定义,或者是一个含义为 \relax 的宏,或者是一个替换文本为空的无参数宏,则扩展为 true,否则扩展为 false。

这将 的测试扩展\ifdefempty为包括未定义的控制序列(与原始和不可扩展相反,它们在本测试的意义上不是 void),或等同于\relax。在后一种连接中使用“宏”一词是不幸的,因为它们不是技术意义上的宏(不可扩展)。这样的控制序列应该通过以下方式创建:

<any of the above for \ifdefempty>
\let\cs\relax
\csname cs\endcsname %If \cs were previously undefined, this makes it \relax

或者,当然,绝不已创建,因此仍未定义。

相关内容