\ifx\\#1\\ 代表什么?

\ifx\\#1\\ 代表什么?

以下用法\ifx可以在多个软件包以及本网站的答案中找到。这种语法到底是什么意思?有什么替代方案和缺点吗?

\newcommand{\mycommand}[2][]{%
  \ifx\\#1\\
    <true>
  \else
    <false>
  \fi
  % ...
}

(我其实知道答案,但认为这个问题应该存在这里。它会时不时地出现。如果它没有得到完全的回答,我将在几天后发布自己的答案。)

答案1

这是无数种检查参数是否为空的方法之一。几乎所有方法都有一些缺点:在这种情况下,参数不能是\\

它做什么\ifx?它比较后面的两个 token,无需扩大它们\meaning如果两个标记在或 的意义上相等\show,则测试返回成功:

  • 如果它们是字符(或\let字符的控制序列),它们必须代表相同的(字符代码、类别代码)对

  • 如果它们是控制序列(但不是\let字符),它们必须具有相同的含义;情况太多,无法全部列出。

在分析宏之前,我们应该了解一下 TeX 条件:抽象形式是

\ifZ<test><true text>\else<false text>\fi

其中\ifZ表示原始条件之一。 可以<test>采用多种形式,具体取决于\ifZ(在某些情况下为空);重要的是 是<true text>从 结尾到 的所有内容<test>\else\fiif\else缺失)。

那么让我们看看当我们调用时会发生什么\mycommand{abc},也就是说,默认参数(空)被替换为#1:TeX 看到的标记是

\ifx\\\\<true>\else<false>\fi

当然测试是正确的,因为后面的标记\ifx都是\\

当我们调用 时\mycommand[xyz]{abc},TeX 看到的是

\ifx\\xyz\\<true>\else<false>\fi

和 TeX 相比\\x它们是不同的。但现在<true text>

yz\\<true>

(记住:<true text>是从测试到的\else)并且它将被完全忽略。

这个测试非常安全,因为它不进行扩展;但是,如果用户调用\mycommand[\\]{abc},它可能会失败,因此通常会使用不同的分隔符标记,这些分隔符不应潜入用户的输入(例如\uchyph\vfuzz)。另一个类似的测试可能是

\if\relax\noexpand#1\relax

但需要注意的是\if 扩展下一个标记,直到剩下两个不可扩展的标记。第一个标记是\relax,它是不可扩展的。第二个标记将是 扩展后的结果\noexpand,即 的第一个标记#1(如果非空)但不可扩展;如果#1为空,则\noexpand应用于\relax,再次导致 ,\relax因为它是不可扩展的。

在两种情况下,都会保留一些 token(\\第一种情况下是保留,\relax第二种情况下是保留)。最安全测试是

\if\relax\detokenize{#1}\relax

因为非空的扩展#1可以绝不给出第一个相当于的标记\relax:即使#1\relax\detokenize{\relax}也会给出细绳 \relax(其中第一个标记是字符\)。

同样,如果#1为空,则测试\relax与进行比较\relax;如果#1不为空,则将忽略 之前的所有内容\else。当然,它要求运行带有 e-TeX 扩展的引擎:它不适用于“Knuth TeX”。

答案2

\ifx <command> #1 <command> 
  <code for #1 is empty>
\else
  <code for #1 is _not_ empty>
\fi

<command>也可以是

\ifx\relax#1\relax

如果#1为空(或不存在),则为\relax=\relax真。如果#1不为空,则为\relax=#1假(除#1=\relax),以下内容\relax无害,因为它不执行任何操作。

使用\ifx\\#1\\LaTeX 内核对文件名的扩展名进行测试:

\def\test#1.#2\\{%
  \ifx\\#2\\ 
    <no extension #2 is empty, because \\=\\>
  \else
    <extension is #2>
  \fi

相关内容