5

I'm defining a new command which should take an optional list of arguments (integers or ranges):

\doit[3,5-7,9]{something}

What I have so far:

\def\doit{\@ifnextchar[{\@with}{\@without}}
\def\@with[#1]#2{
  ...
}
\def\@without#1{
}

In the with case, how can I iterate over the optional arguments? How can I distinguish between integers and ranges? Do I need to do the parsing manually or there are tools which can help me?

2 Answers2

7

If changing the - character to ,..., is feasible for you, you can directly and easily benefit from the power of the pgffor module of TikZ/PGF. Please check the manual for other types that are supported. Here is an example with also non-numeric lists:

\documentclass{article}
\usepackage{pgffor}
\makeatletter
\def\doit{\@ifnextchar[{\@with}{\@without}}
\def\@with[#1]#2{
#2 have the following list:%
\foreach \x in {#1}{
\x,%
    }
}
\def\@without#1{
#1, I have no optional arguments.
}
\makeatother

\begin{document}
\doit[1,...,5,7]{I}

\doit{Ahem}

\doit[1,3$\pi$,4$\pi$,...$\pi$,7$\pi$,e,f,...,i]{Also I}
\end{document}

enter image description here

percusse
  • 157,807
5

You can use the splitting argument facilities provided by xparse:

\documentclass{article}
\usepackage{xparse}
\newcommand{\doittemp}{}
\NewDocumentCommand{\doit}{>{\SplitList{,}}om}{%
  \renewcommand\doittemp{#2}%
  \IfNoValueTF{#1}
    {\par (main argument \doittemp)}
    {\ProcessList{#1}{\doitauxi}}%
}
\NewDocumentCommand{\doitauxi}{>{\SplitArgument{1}{-}}m}{\doitauxii #1}
\NewDocumentCommand{\doitauxii}{mm}{%
  \IfNoValueTF{#2}
   {\par Single number #1 (main argument \doittemp)}
   {\par Range #1--#2 (main argument \doittemp)}%
}

\begin{document}
\doit{No optional argument}
\bigskip

\doit[1,2]{Two single numbers}

\bigskip

\doit[1,3-5]{Single number and range}

\bigskip

\doit[1-3,5-10]{Two ranges}

\end{document}

enter image description here

egreg
  • 1,121,712