5

I'm trying to define a command that will take 3 arguments each one possibly empty. An empty argument will slightly modify the output. Let me give a non-working example :

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

And this is what I would like to get :

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

But obviously it doesn't work. I'd like, as much as possible, to call this function with only one type of bracket (since I will always write the 3 pairs of bracket even if they are empty). As far as I'm concern, I consider that there's no optional arguments in it, only mandatory arguments that are possibly empty. I pretty sure I'm not doing things right but I really don't get the idea of this \newcommand function.

Thanks for any help.

5

While xparse is one way to go, here's another approach:

\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}

enter image description here The \expandafter\ifx\expandafter\relax\detokenize{#1}\relax is a nice way of testing for an empty argument to your macro. Essentially if #1 is empty, then the \detokenize{#1} essentially vanishes and the test becomes

\ifx\relax\relax

which will test to true.

If #1 is not empty, then \detokenize will result in a token that is not going to result in a true value when compared with \relax.

To make your code a little more readable, you could define your own test commnad sequence:

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

and then your \foo could be written as

\newcommand\foo[3]{%%
  \textbf{bar}(%%
  \aeifempty{#1}{}{#1,}%%
  #2)
  \aeifempty{#3}{}{\cap#3}}
  • \if\relax\detokenize{#1}\relax is as good and simpler – egreg Mar 7 '16 at 16:36
  • By the way, the spacing around the intersection symbol is wrong. – egreg Mar 7 '16 at 18:35
  • @egreg Hmm. I hadn't paid attention to that. But, now that I see it, I wonder why. Do I need to {} around it so it behaves as a binary operation? – A.Ellett Mar 7 '16 at 20:25
  • @egreg I see the problem!! – A.Ellett Mar 7 '16 at 20:27
3

If you use xparse, you need not define your own test for emptyness:

\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}

The function \tl_if_blank:nF returns the second argument if and only if the first argument is not blank (a sequence of zero or more blank spaces).

enter image description here

Of course, for the particular application just two arguments would be needed:

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

and \foo{a,b}{c}, \foo{b}{c} or \foo{b}{} would do.

2

With xparse and \NewDocumentCommand it is possible to define a macro with two optional and one mandatory argument, where the latter is the middle one:

\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}

But this definition can be problematic if the command is followed by a literal [ the is part of the equation. In that case there must be a space between the mandatory argument and the opening bracket:

$\foo{b} [x,y,z]$
  • I believe with xparse a following [ shouldn't be a problem if there is a space before it. – A.Ellett Mar 7 '16 at 16:17
  • @A.Ellett: indeed :-) I changed my answer accordingly. – Tobi Mar 7 '16 at 16:31
0

The OP didn't say what packages, if any, were used.

The OP's code works for me with \usepackage{xifthen}.

It doesn't work with \usepackage{ifthen}, which doesn't implement \isempty.

With \usepackage{ifthen}, you can do

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

but the xifthen version is more efficient because \isempty doesn't expand its argument, but \equal does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.