7

I would like to have a single command that can take either 1, 2, or 3 arguments and do something different for each number of arguments.

\c{a}       -> C_a
\c{a}{b}    -> C_{a}^{[b]}
\c{a}{b}{c} -> C_{a,c}^{[b]}

Since Latex has no command overloading, I decided that optional arguments are good enough:

\c{a}       -> C_a
\c[b]{a}    -> C_{a}^{[b]}
\c[c][b]{a} -> C_{a,c}^{[b]}

I found that this great answer using xparse might do exactly what I need. However his answer works only for 2 optional arguments. He mentions how to extend it to any number of arguments, but I couldn't figure it out. I tried:

\usepackage{xparse}
....
\DeclareDocumentCommand \c { o o m } {%
  \IfNoValueTF {#1} {%
    \IfNoValueTF {#2} {%
      C_{#3}%
     }{%
      C_{#3}^{[#2]}%
  }%
  }{%
    C_{#2, #3}^{[#1]}%
  }% 
}

$\c{a} \c[b]{a} \c[c][b]{a}$ 

But it seems that I cannot get the branch with two arguments to work:

enter image description here

What am I doing wrong?

  • In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handle \c{a}bc? Shall this mean \c has one arg and the one-arg-call to \c is trailed by letters b and c which do not form args of \c? Shall this mean a three-argument-call to \c with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e., \c{{a}{b}{c}}, but then you need to specify behavior for other cases and spaces as well. – Ulrich Diez Aug 31 '18 at 16:56
7

You should start from examining #2 rather than #1, because #2 only can have a value if #1 has, too.

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand \C { o o m } {%
  \IfNoValueTF{#2}
   {%
    \IfNoValueTF {#1}
     {%
      C_{#3}%
     }
     {%
      C_{#3}^{[#1]}%
     }%
   }
   {%
    C_{#3, #1}^{[#2]}%
   }% 
}

\begin{document}

$\C{a} \quad \C[b]{a} \quad \C[c][b]{a}$ 

\end{document}

And don't use \DeclareDocumentCommand to override the meaning of \c: you'll regret it when you have to cite some French or Turkish author with “ç” in their name.

enter image description here

1

You wish to define a macro \c. But \c is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as \c.
Instead I will refer to the macro in question as \macroc.


Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?

After defining \newcommand\foo[1]{This is argument 1: #1.},
\foo{b} will yield the same result as
\foo b.

After defining \newcommand\bar[2]{This is argument 1: #1. This is argument 2: #2.}, the following calls will all yield the same result:
\bar{a}{b}
\bar a{b}
\bar {a}b
\bar ab
\bar{a} {b}
\bar a {b}
\bar {a} b
\bar a b

This is because

  1. you don't need braces when undelimited arguments consist of a single token.
  2. (La)TeX does discard space tokens preceding undelimited arguments.

When called as \macroc{a}{b}c—how shall \macroc "know" whether the user intends to have c as \macroc's third argument which consists of the single token c or whether the user intends to have \macroc called with only two arguments, namely {a} and {b} while c shall not be considered a third argument?

The situation is ambiguous.

You can turn the situation into something unambiguous by having \macroc process only one undelimited argument and having \macroc check whether that argument in turn is of one of the patterns

{⟨argument 1⟩}

{⟨argument 1⟩}{⟨argument 2⟩}

{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}

and having \macroc act accordingly in case one of these patterns is detected and having \macroc deliver an error-message otherwise.

I.e.,

\macroc{{⟨argument 1⟩}}

\macroc{{⟨argument 1⟩}{⟨argument 2⟩}}

\macroc{{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}}


With the example below, \macroc does process one undelimited argument.

Syntax: \macroc{⟨argument⟩}.

In case ⟨argument⟩ is of pattern {⟨argument 1⟩},
\macrocatonearg{⟨argument 1⟩} will be carried out.

In case ⟨argument⟩ is of pattern {⟨argument 1⟩}{⟨argument 2⟩}, \macrocattwoargs{⟨argument 1⟩}{⟨argument 2⟩} will be carried out.

In case ⟨argument⟩ is of pattern {⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}, \macrocatthreeargs{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩} will be carried out.

In all other cases an error-message will inform the user about a syntax-error.

Thus you can do, e.g., :

\macroc{{a}}

\macroc{{a}{b}}

\macroc{{a}{b}{c}}

\documentclass{article}

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@gobble, \UD@gobbletwo, \UD@gobblethree
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@gobble[1]{}%
\newcommand\UD@gobbletwo[2]{}%
\newcommand\UD@gobblethree[3]{}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%=============================================================================
%% \macroc for processing one argument within which
%%  you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
\newcommand\macrocatonearg[1]{C_#1}%
\newcommand\macrocattwoargs[2]{C_{#1}^{[#2]}}%
\newcommand\macrocatthreeargs[3]{C_{#1,#3}^{[#2]}}%
\newcommand\macrocatsyntaxerror{%
  \@latex@error{Incorrect Syntax}{Specify either one or two or three arguments that are nested in braces.}%
}%
\newcommand\macroc[1]{%
   \UD@CheckWhetherBrace{#1}{%
      \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobble#1}{%
         \macrocatonearg#1%
      }{%
        \expandafter\UD@CheckWhetherBrace\expandafter{\UD@gobble#1}{%
          \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletwo#1}{%
            \macrocattwoargs#1%
          }{%
            \expandafter\UD@CheckWhetherBrace\expandafter{\UD@gobbletwo#1}{%
               \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobblethree#1}{%
                 \macrocatthreeargs#1%
               }{\macrocatsyntaxerror}%
            }{\macrocatsyntaxerror}%
          }%
        }{\macrocatsyntaxerror}%
      }%
   }{\macrocatsyntaxerror}%
}%
\makeatother
\begin{document}

\verb|$\macroc{{a}}$|: $\macroc{{a}}$ \bigskip

\verb|$\macroc{{a}{b}}$|: $\macroc{{a}{b}}$ \bigskip

\verb|$\macroc{{a}{b}{c}}$|: $\macroc{{a}{b}{c}}$ \bigskip

% Syntax-errors:
% 
% $\macroc{{a}{b}{c}{d}}$
%
% $\macroc{ {a}}$
% 
% $\macroc{{a} {b}}$
%
% $\macroc{a}$
%
% $\macroc{}$

\end{document}

enter image description here

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.