TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question
up vote 5 down vote accepted

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}}
share|improve this answer
    
\if\relax\detokenize{#1}\relax is as good and simpler – egreg Mar 7 at 16:36
    
By the way, the spacing around the intersection symbol is wrong. – egreg Mar 7 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 at 20:25
    
@egreg I see the problem!! – A.Ellett Mar 7 at 20:27

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.

share|improve this answer

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]$
share|improve this answer
    
I believe with xparse a following [ shouldn't be a problem if there is a space before it. – A.Ellett Mar 7 at 16:17
    
@A.Ellett: indeed :-) I changed my answer accordingly. – Tobi Mar 7 at 16:31

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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