定义具有多个排序的强制参数的新命令,这些参数可以为空

定义具有多个排序的强制参数的新命令,这些参数可以为空

我正在尝试定义一个命令,该命令将接受 3 个参数,每个参数可能为空。空参数将稍微修改输出。让我举一个不起作用的例子:

\newcommand{\foo}[3]{
\textbf{bar}(
  \ifthenelse{\isempty{#1}}
    {}
    {#1, }
    #2)
    \ifthenelse{\isempty{#3}}
    {}
    {\cap #3}
}

这就是我想要得到的:

  • \foo{a}{b}{c}=>foo1
  • \foo{}{b}{}=>foo2
  • \foo{}{b}{c}=>foo3

但显然它不起作用。我希望尽可能只使用一种括号来调用此函数(因为即使它们是空的,我也总是会写出 3 对括号)。就我而言,我认为其中没有可选参数,只有可能为空的强制参数。我很确定我做得不对,但我真的不明白这个\newcommand函数的思路。

谢谢你的帮助。

答案1

虽然xparse这是一种方法,但还有另一种方法:

\documentclass{article}
\newcommand\foo[3]{%%
  \textbf{bar}(%%
  \expandafter\ifx\expandafter\relax\detokenize{#1}\relax
  \else
    #1,
  \fi 
  #2)
  \expandafter\ifx\expandafter\relax\detokenize{#3}\relax
  \else
  \cap#3
  \fi}


\pagestyle{empty}
\begin{document}

  $\foo{a}{b}{c}$

  $\foo{}{b}{}$

  $\foo{}{b}{c}$

\end{document}

在此处输入图片描述\expandafter\ifx\expandafter\relax\detokenize{#1}\relax是测试宏是否为空参数的好方法。本质上,如果#1为空,则\detokenize{#1}本质上消失,测试变为

\ifx\relax\relax

测试结果为真。

如果#1不为空,那么\detokenize将导致与相比不会产生真实值的标记\relax

为了使您的代码更具可读性,您可以定义自己的测试命令序列:

\newcommand\aeifempty[3]{%%
  \expandafter\ifx\expandafter\relax\detokenize{#1}\relax
    #2%%
  \else
    #3%%
  \fi}

然后你\foo可以写成

\newcommand\foo[3]{%%
  \textbf{bar}(%%
  \aeifempty{#1}{}{#1,}%%
  #2)
  \aeifempty{#3}{}{\cap#3}}

答案2

如果您使用xparse,则不需要定义自己的空性测试:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\ifnotblank}{mm}
 {
  \tl_if_blank:nF { #1 } { #2 }
 }
\ExplSyntaxOff

\NewDocumentCommand{\foo}{mmm}
 {%
  \operatorname{\mathbf{bar}}(\ifnotblank{#1}{#1,}#2)%
  \ifnotblank{#3}{\cap #3}%
 }

\begin{document}

\begin{tabular}{@{}ll@{}}
\verb|\foo{a}{b}{c}| & $\foo{a}{b}{c}$ \\
\verb|\foo{}{b}{}|   & $\foo{}{b}{}$ \\
\verb|\foo{}{b}{c}|  & $\foo{}{b}{c}$ \\
\verb|\foo{ }{b}{ }| & $\foo{}{b}{}$ \\
\verb|\foo{ }{b}{c}| & $\foo{}{b}{c}$
\end{tabular}

\end{document}

\tl_if_blank:nF当且仅当第一个参数不为空(零个或多个空格的序列)时,该函数才返回第二个参数。

在此处输入图片描述

当然,对于特定的应用来说需要的参数:

\NewDocumentCommand{\foo}{mm}{%
  \operatorname{\mathbf{bar}}(#1)%
  \notblank{#2}{\cap#2}%
}

\foo{a,b}{c}\foo{b}{c}或者\foo{b}{}都可以。

答案3

使用xparse\NewDocumentCommand可以定义一个包含两个的宏选修的和一个强制的参数,其中后者是中间的参数:

\documentclass{article}

\usepackage{amsmath}

\usepackage{xparse}

\NewDocumentCommand{\foo}{ o m o }{%
   \text{bar}(%
   \IfValueT{#1}{#1,}%
   #2)%
   \IfValueT{#3}{\cap #3}%
}

\begin{document}
$\foo[a]{b}[c]$

$\foo{b}$

$\foo[a]{b}$

$\foo{b}[c]$
\end{document}

如果命令后面跟着文字[(是等式的一部分),则此定义可能会有问题。在这种情况下,强制参数和左括号之间必须有一个空格:

$\foo{b} [x,y,z]$

答案4

OP 并未说明使用了什么包(如果有的话)。

OP 的代码对我有用\usepackage{xifthen}

它不适用于\usepackage{ifthen}不实现的\isempty

使用\usepackage{ifthen},你可以做

\newcommand{\foo}[3]{
\textbf{bar}(
  \ifthenelse{\equal{#1}{}}
    {}
    {#1, }
    #2)
    \ifthenelse{\equal{#3}{}}
    {}
    {\cap #3}
}

但是该xifthen版本效率更高,因为\isempty它不会扩展其参数,但\equal会扩展。

相关内容