[Tex/LaTex] newcommand with comma separated argument, and optional arguments

argumentscomma-separated listmacrosoptional argumentsrobust-commands

I want to define a command (not with \def) the simplest possible way that it

  • takes arguments separated by a comma,
  • supports an optional argument (the first one).

maybe another solution with extra optional arguments which are not necessarily the firsts will be welcome in the future.

I want to have something like this: \mycmd[opt arg1, opt arg2]{arg3, arg4}.

I already saw https://tex.stackexchange.com/a/29975/92620 and https://tex.stackexchange.com/a/2860/92620.

\documentclass{report}
\newcommand\mycmd[4][]{optional: #1\\ mandatory: #2 - #3 - #4}

\begin{document}
\mycmd[optional arg]{second arg,third arg,fourth arg}
\end{document}

Best Answer

The following example uses \comma@parse of package kvsetkeys to parse the comma separated argument lists.

\documentclass{report}
\usepackage{kvsetkeys}% provides \comma@parse
\usepackage{etexcmds}% provides \etex@unexpanded

\makeatletter
\newcount\arg@count
\newcommand{\arg@parser}[1]{%
  \advance\arg@count\@ne
  \expandafter\let\csname arg\romannumeral\arg@count\endcsname\comma@entry
}
% \mycmd[opt arg1, opt arg2]{arg 3, arg4, arg5}
\newcommand\mycmd[2][]{% Default is empty and will be configured later
  % Set default values
  \arg@count=\z@
  \comma@parse{default1, default2}\arg@parser % Default values
  % Parse optional argument
  \arg@count=\z@
  \comma@parse{#1}\arg@parser
  \ifnum\arg@count>2 %
    \@latex@error{Too many optional arguments}{%
      The macro \string\mycmd\space got \the\arg@count\space
      optional arguments,\MessageBreak
      but expected are 2 optional arguments.\MessageBreak
      \@ehd
    }%
  \fi
  % Mandatory arguments
  \arg@count=2
  \comma@parse{#2}\arg@parser
  \ifnum\arg@count=5 %
  \else
    \@latex@error{Wrong number of mandatory arguments}{%
      The macro \string\mycmd\space got \the\numexpr\arg@count-2\relax\space
      mandatory arguments,\MessageBreak
      but expected are 3 mandatory arguments.\MessageBreak
      \@ehd
    }%
  \fi
  % Either using \argi, \argii, \argiii, \argiv, \argv
  % or
  % \@mycmd\argi\argii\argiii\argiv\argv
  % or
  \edef\process@me{%
    \noexpand\@mycmd
    {\etex@unexpanded\expandafter{\argi}}%
    {\etex@unexpanded\expandafter{\argii}}%
    {\etex@unexpanded\expandafter{\argiii}}%
    {\etex@unexpanded\expandafter{\argiv}}%
    {\etex@unexpanded\expandafter{\argv}}%
  }%
  \process@me
}
\newcommand{\@mycmd}[5]{%
  \noindent
  optional: #1 -- #2\\
  mandatory: #3 -- #4 -- #5%
}
\makeatother

\begin{document}
  \mycmd[optional arg]{third arg,fourth arg, fifth arg }
\end{document}

Result

Remarks:

  • The list of optional arguments can be shorter, the omitted arguments gets default values.

  • \comma@parse trims the arguments by removing leading and trailing space.

  • \comma@parse removes empty entries. A workaround for empty arguments is using \relax or \empty.

Related Question