我正在尝试定义一个命令,该命令将接受 3 个参数,每个参数可能为空。空参数将稍微修改输出。让我举一个不起作用的例子:
\newcommand{\foo}[3]{
\textbf{bar}(
\ifthenelse{\isempty{#1}}
{}
{#1, }
#2)
\ifthenelse{\isempty{#3}}
{}
{\cap #3}
}
这就是我想要得到的:
\foo{a}{b}{c}
=>\foo{}{b}{}
=>\foo{}{b}{c}
=>
但显然它不起作用。我希望尽可能只使用一种括号来调用此函数(因为即使它们是空的,我也总是会写出 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
会扩展。