I am reading many entries here on comma-separated list of arguments in new commands. I cannot get them to adapt to my needs, so here I come with my question.

I'd like a command like so:

\eqsRef{equ:name_one, equ:name_two, equ:name_three} % with any number of arguments

where the 'equ:foo_bar' things are equation labels, always including the colon and often with the underscore character, which produces something equivalent to this:

Eqs.~(\ref{equ:name_one}, \ref{equ:name_two}, \ref{equ:name_three})

but with any number of arguments. That is, which prints e.g.

Eqs. (3, 45, 62)

if the provided equation labels happen to be those equation numbers.

Bonus (not really needed but...): if only one argument is provided, then write 'Eq.~' instead of 'Eqs.~'.

I will happily accept solutions using or not using extra packages.

  • You might also look at the xstring package. – John Kormylo Nov 13 at 21:01
  • 1
    Have you seen the cleveref package? – TeXnician Nov 14 at 6:41
up vote 3 down vote accepted

The following example defines \eqsRef to take a list of <label>s and processes this list using etoolbox's \docsvlist. Accommodation for pluralization is made by counting the number of <label>s used.

enter image description here

\documentclass{article}

\usepackage{etoolbox,amsmath}

\newcounter{eqncount}

% \eqsRef{<csv of labels to equations>}
\newcommand{\eqsRef}[1]{%
  \setcounter{eqncount}{0}% Restart equation counter
  \renewcommand*{\do}[1]{\stepcounter{eqncount}}% Step equation reference counter
  \docsvlist{#1}% Count number of equation references
  Eq%
  \ifnum\value{eqncount}>1
    s% Plural
  \fi
  .\nobreakspace
  % https://tex.stackexchange.com/a/89187/5764
  \def\eqnrefdelim{\def\eqnrefdelim{, }}%
  \renewcommand{\do}{\eqnrefdelim\ref}%
  \textup{(}%
    \docsvlist{#1}%
  \textup{)}%
}

\begin{document}

\begin{align}
  f(x) \label{eqn:first} \\
  s(x) \label{eqn:second} \\
  t(x) \label{eqn:third} \\
  l(x) \label{eqn:last}
\end{align}

\eqsRef{eqn:first, eqn:second, eqn:last}

\eqsRef{eqn:third}

\end{document}

The references are set inside a \textup{(}...\textup{)} series, meaning the parentheses will always be upright. Other formatting considerations can also be introduced, as needed.

The input is split at commas, then a new sequence is made with each item fed as argument to \ref.

Finally the list is printed; if there is just one item, it is preceded by Eq. otherwise the list is preceded by Eqs..

Leading or trailing spaces around items are ignored. Thus

\eqrefs{equ:name_one, equ:name_two, equ:name_three}
\eqrefs{equ:name_one,equ:name_two,equ:name_three}
\eqrefs{ equ:name_one , equ:name_two, equ:name_three }

are equivalent.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\eqrefs}{m}
 {% #1 = list of labels
  \joansola_eqrefs:n { #1 }
 }

\seq_new:N \l__joansola_eqrefs_in_seq
\seq_new:N \l__joansola_eqrefs_out_seq

\cs_new_protected:Nn \joansola_eqrefs:n
 {
  \seq_set_split:Nnn \l__joansola_eqrefs_in_seq { , } { #1 }
  \seq_set_map:NNn \l__joansola_eqrefs_out_seq \l__joansola_eqrefs_in_seq
   {
    \exp_not:n { \ref{##1} }
   }
  \int_compare:nTF { \seq_count:N \l__joansola_eqrefs_out_seq < 2 }
   { Eq.\nobreakspace }
   { Eqs.\nobreakspace }
  \textup{(\seq_use:Nn \l__joansola_eqrefs_out_seq {,~})}
 }
\ExplSyntaxOff

\begin{document}

\begin{align}
a&=b \label{equ:name_one} \\
c&=d \label{equ:name_two} \\
e&=f \label{equ:name_three}
\end{align}

\eqrefs{equ:name_one, equ:name_two, equ:name_three}

\eqrefs{equ:name_one, equ:name_three}

\eqrefs{equ:name_one}

\end{document}

enter image description here

An approach using package xinttools, part of the xint libraries.

\documentclass{article}

\usepackage{amsmath}

\usepackage{xinttools}

% \eqsRef{<csv of labels to equations>}
\newcommand{\eqsRef}[1]{%
  % First we trim from the input items leading and trailing spaces
  % The argument #1 is allowed to be a macro, say, \mylist, holding
  % the values, because \xintCSVtoList applies expansion to it 
  % (this means the first item will also be submitted to some expansion)
  \oodef\eqsRefinput{\xintCSVtoList{#1}}%
  % count how many items and typeset either Eq. or Eqs.
  Eq\ifnum\xintNthElt{0}{\eqsRefinput}>1
    s% Plural
  \fi
  .\nobreakspace
  \textup{(}%
  % Do now an \xintFor* loop to act upon each item
  \xintFor* ##1 in \eqsRefinput:
  {\xintifForFirst{}{\xintifForLast{ and }{, }}\ref{##1}}%
  \textup{)}%
}%

\begin{document}

\begin{align}
  f(x) \label{eqn:first} \\
  s(x) \label{eqn:second} \\
  t(x) \label{eqn:third} \\
  u(x) \label{eqn:fourth} \\
  l(x) \label{eqn:last}
\end{align}

\eqsRef{eqn:first, eqn:third, eqn:last}

\eqsRef{eqn:third}

\end{document}

enter image description here

You wish comma-list-parsing.

Yeah!! Comma-list-parsing in (La)TeX is fun as

  • you need to take care of spaces surrounding the single items.

  • you need to take care of one pair of braces surrounding an entire single item for providing a means of masking commas and spaces that are parts of names of labels. Also be aware that you can have a "nameless" referencing-label by simply doing \label{} … \ref{}.

  • it always provides an opportunity of reinventing the wheel. ;-)

I took the challenge of doing everything expandably (i.e. none of the loops etc does define temporary macros), without forbidden tokens, without \if…-switches, without extensions like eTeX, without extra packages.

I give no warranties.

If you see the need of editing this post for correcting bugs/errors not related to spelling/not related to the English language but to the code, please drop me a hint. ;-)

(Well, eh, if you see the need of editing this post for correcting bugs/errors related to spelling/related to the English language, you, of course, can drop me a hint, too. ;-) )

\documentclass{article}

\makeatletter
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION LICENCE AND COPYRIGHT
%%
%% Copyright (C) 2018 by  Ulrich W. Diez (ud.usenetcorrespondence@web.de)
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or 
%% (at your option) any later version. 
%% (The latest version of this license is in:
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of 
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status ‘not maintained’.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty — neither for probably included documentation nor for 
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%% EOF SECTION LICENCE AND COPYRIGHT
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION PARAPHERNALIA:
%% 
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@CheckWhetherNull, 
%%    \UD@CheckWhetherBlank
%%==============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
%%------------------------------------------------------------------------------
%% 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 is blank (empty or only spaces):
%%..............................................................................
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \UD@CheckWhetherBlank{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that
%%                        argument which is to be checked is blank>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is not blank}%
\newcommand\UD@CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\UD@secondoftwo
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#1{}.}%
}%
%%
%% EOF SECTION PARAPHERNALIA
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%
%%  - REQUIRES SECTION PARAPHERNALIA.
%% 
%%   The obscure case of removing several leading/trailing spaces was taken 
%%   into consideration.
%%
%%   Removal of spaces was implemented in a way where no brace-stripping from
%%   the arguments takes place. 
%%   Explicit-catcode-1/2-character-token-pairs remain untouched.
%%
%%   Spaces interspersing the argument or hidden within braces will be left in
%%   place.
%%
%%   The arguments themselves do not get expanded.
%%
%%   (For some obscure reason I don't remember any more I needed this in the
%%    past.)
%%
%%==============================================================================
%% Check whether brace-balanced argument starts with a space-token
%%..............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%==============================================================================
%% \UD@TrimAllLeadSpace{<action>}{<argument>} 
%%..............................................................................
%%   expandably removes all leading spaces from  <argument> in case at least
%%   one leading space is present. 
%%   Then
%%     <action>{<argument without leading spaces>}
%%   is performed.
%%==============================================================================
\newcommand\UD@TrimAllLeadSpace[2]{%
  \romannumeral0\UD@TrimAllLeadSpaceLoop{#2}{#1}%
}%
\newcommand\UD@TrimAllLeadSpaceLoop[2]{%
  \UD@CheckWhetherLeadingSpace{#1}%
                            {%
                              \expandafter\UD@TrimAllLeadSpaceLoop
                              \expandafter{\UD@removespace#1}{#2}%
                            }%
                            { #2{#1}}%
}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%==============================================================================
%% \UD@TrimAllTrailSpace{<action>}{<argument>} 
%%..............................................................................
%%   expandably removes all trailing spaces from  <argument> in case at least
%%   one trailing space is present. 
%%   Then
%%     <action>{<argument without trailing spaces>}
%%   is performed.
%%==============================================================================
\newcommand\UD@TrimAllTrailSpace[2]{%
   \romannumeral0\UD@TrimTrailSpaceLoop{#2}{#1}%
}%
%%------------------------------------------------------------------------------
%% \UD@TrimTrailSpaceLoop{<list of space-delimited arguments>}{<action>}
%%..............................................................................
%%   both extracts the first space-delimited argument from the <list of space-
%%   delimited arguments> as {<current argument with one trailing space 
%%   removed>} and removes it from the <list of space-delimited arguments> for
%%   obtaining the <remaining list of space delimited arguments> and passes 
%%   these two things and an empty list of <arguments preceding the current
%%   argument gathered so far> and the <action> to perform at the end of the 
%%   iteration to \UD@CheckWhetherLastSpaceDelimitedItem.
%%
%%   \UD@CheckWhetherLastSpaceDelimitedItem in turn does choose the next
%%   action.
\newcommand\UD@TrimTrailSpaceLoop[2]{%
  \UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1 \UD@SeLDom}{%
    \expandafter\UD@CheckWhetherLastSpaceDelimitedItem
    \expandafter{\UD@RemoveTokensTillNextSpace.#1 }%
  }{}{#2}%
}%
%%------------------------------------------------------------------------------
%% Macros for \UD@ObtainFirstSpaceDelimitedTokenSetLoop.
%%
\newcommand*\UD@RemoveTokensTillNextSpace{}%
  \long\def\UD@RemoveTokensTillNextSpace#1 {}%
\newcommand*\UD@BraceStripRemoveNextSpace{}%
  \long\def\UD@BraceStripRemoveNextSpace#1 {#1}%
\newcommand*\UD@GetFirstSpaceDelimitedTokenSet{}%
  \long\def\UD@GetFirstSpaceDelimitedTokenSet#1 #2\UD@SeLDom{#1 }%
\newcommand\UD@gobbledot{}%
  \def\UD@gobbledot.{}%
%%------------------------------------------------------------------------------
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop%
%%     {<list of space delimited arguments>}%
%%     {<action>}%
%%
%% -> <action>{<first element of list of space delimited arguments>}%
%%...............................................................................
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop does--without unwanted brace-re-
%% moval--append the first space delimited argument from a
%% <list of space delimited arguments> as brace-delimited argument behind
%% a set of tokens given as <action>.
\newcommand\UD@ObtainFirstSpaceDelimitedTokenSetLoop[1]{%
  \expandafter\UD@CheckWhetherNull
  \expandafter{\UD@RemoveTokensTillNextSpace#1}{%
    \expandafter\expandafter\expandafter\UD@Exchange
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\expandafter{%
    \expandafter\UD@gobbledot\UD@BraceStripRemoveNextSpace#1}}%
  }{%
    \expandafter\UD@ObtainFirstSpaceDelimitedTokenSetLoop
    \expandafter{\UD@GetFirstSpaceDelimitedTokenSet#1}%
  }%
}%
%%------------------------------------------------------------------------------
%% \UD@CheckWhetherLastSpaceDelimitedItem
%%    {<remaining list of space delimited arguments>}%
%%    {<current argument with one trailing space removed>}%
%%    {<arguments preceding the current argument gathered
%%      so far>}%
%%    {<action>}%
%%..............................................................................
%% Case 1: <remaining list of space delimited arguments> is
%%         empty.
%%         We are done: Thus:
%%         <space>% for terminating \romannumeral-expansion, and
%%         <action>{<arguments preceding the current argument gathered so
%%                   far><current argument with one trailing space removed>}
%% Case 2: <remaining list of space delimited arguments> consists of a single 
%%         space.
%%         A trailing space was removed. There may be more. Thus:
%%         \UD@TrimTrailSpaceLoop{%
%%           <arguments preceding the current argument gathered so
%%           far><current argument with one trailing space removed>%
%%         }{<action>}%
%% Neither case 1 nor case 2: 
%%         The <current argument with one trailing space  removed> is not the
%%         last argument of the list, thus:
%%         For the next iteration 
%%         - attach it and a trailing space to the <arguments preceding the
%%           current argument gathered so far>,
%%         - get the first space delimited argument of the <remaining list of 
%%           space delimited arguments> as  <current argument with one trailing
%%           space removed>
%%         - remove that first space delimited argument from the <remaining list 
%%           of space delimited arguments>
\newcommand\UD@CheckWhetherLastSpaceDelimitedItem[4]{%
  \UD@CheckWhetherNull{#1}{ #4{#3#2}}{%
    \UD@CheckWhetherLeadingSpace{#1}{%
      \expandafter\UD@CheckWhetherNull
      \expandafter{\UD@removespace#1}{\UD@firstoftwo}{\UD@secondoftwo}%
    }{\UD@secondoftwo}%
    {\UD@TrimTrailSpaceLoop{#3#2}{#4}}%
    {%
      \UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1\UD@SeLDom}{%
        \expandafter\UD@CheckWhetherLastSpaceDelimitedItem
        \expandafter{\UD@RemoveTokensTillNextSpace.#1}%
      }{#3#2 }{#4}%
    }%
  }%
}%
%%==============================================================================
%% \UD@TrimAllSurroundSpace{<action>}{<argument>} 
%%..............................................................................
%%   expandably removes all leading and trailing spaces from  <argument> in
%%   case at least one leading space is present. 
%%   Then
%%     <action>{<argument without leading and trailing spaces>}
%%   is performed.
%%==============================================================================
\newcommand\UD@TrimAllSurroundSpace[2]{%
  \romannumeral\UD@TrimAllLeadSpace{\UD@TrimAllTrailSpace{0 #1}}{#2}%
}%
%%
%% EOF SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION EXPANDABLE EXTRACTION OF FIRST ITEM OF COMMA-LIST.
%%
%%  - REQUIRES SECTION PARAPHERNALIA.
%%  - REQUIRES SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%% 
%%-----------------------------------------------------------------------------
%% Extract first inner comma-delimited argument:
%%
%% \UD@ExtractFirstCommaArg{<action>}{<comma list>}
%%
%% yields:
%% 
%% <action>{<first item/first comma-delimited argument from comma
%%           list with surrounding spaces and one level of surroundinng
%%           braces removed if present>}
%%
%% <comma-list> is considered a sequence of comma-delimited arguments.
%%
%% The <first item/first comma-delimited argument from comma list> 
%% will be extracted. The remainder of the <comma list> will be discarded.
%%
%% Then space tokens surrounding the <first item/first comma-delimited
%% argument from comma list> will be removed.
%%
%% If removal of surrounding spaces yields emptiness, no tokens will be
%% delivered.
%%
%% If removal of surrounding spaces does not yield emptiness, 
%%   - one pair of braces surrounding the entire result of space-removal
%%     will be removed if present!!!!!
%%
%%   - Then the result thereof, no matter if empty or not, will be wrapped 
%%     in braces and passed on to <action>.
%%
%% This implies you can have <comma-delimited arguments> contain
%% emptiness or commas and spaces by nesting them into braces.
%%
%% Examples:
%%
%%   \UD@ExtractFirstCommaArg{<action>}{,A,B,C,D,E} yields no token at all
%%
%%   \UD@ExtractFirstCommaArg{<action>}{{},A,B,C,D,E} yields <action>{}
%%
%%   \UD@ExtractFirstCommaArg{<action>}{A,B,C,D,E} yields  <action>{A}
%%
%%   \UD@ExtractFirstCommaArg{<action>}{{AB},C,D,E} yields  <action>{AB}
%%
%%   \UD@ExtractFirstCommaArg{<action>}{  AB  ,C,D,E} yields  <action>{AB}
%%
%%   \UD@ExtractFirstCommaArg{<action>}{  {AB}  ,C,D,E} yields  <action>{AB}
%%
%%   \UD@ExtractFirstCommaArg{<action>}{ { A, B } ,C,D,E} yields  <action>{ A, B }
%%
%%   \UD@ExtractFirstCommaArg{<action>}{ { {AB} } ,C,D,E} yields  <action>{ {AB} }
%% 
%% Due to \romannumeral0-expansion, the result will be delivered after
%% two expansion-steps/after having \UD@ExtractFirstCommaArg "hit" via
%% two \expandafter(-chains).
%%.............................................................................
\newcommand\UD@gobbletocomma{}\long\def\UD@gobbletocomma#1,{}%
\newcommand\UD@removecomma{}\long\def\UD@removecomma#1,{#1}%
\newcommand\UD@removebracesNrmstop[2]{%
  \UD@CheckWhetherNull{#2}{%
    0 %
  }{%
    \expandafter\UD@Exchange
    \expandafter{%
      \expandafter{\UD@removecomma#2,}%
    }{0 #1}%
  }%
}%
\newcommand\UD@RemoveFromCommaTillUD@SelDOm{}%
\long\def\UD@RemoveFromCommaTillUD@SelDOm#1,#2\UD@SelDOm{#1,}%
\newcommand\UD@ExtractFirstCommaArg[2]{%
  \romannumeral%
  \UD@ExtractFirstCommaArgLoop{.#2,\UD@SelDOm}{#1}%
}%
\newcommand\UD@ExtractFirstCommaArgLoop[2]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletocomma#1}%
  {%
     \expandafter\expandafter\expandafter\UD@Exchange
     \expandafter\expandafter\expandafter{%
     \expandafter\expandafter\expandafter{%
     \expandafter\UD@gobbledot\UD@removecomma#1}}%
     {\UD@TrimAllSurroundSpace{%
       \UD@removebracesNrmstop{#2}%
     }}%
  }%
  {%
    \expandafter\UD@ExtractFirstCommaArgLoop
    \expandafter{\UD@RemoveFromCommaTillUD@SelDOm#1}{#2}%
  }%
}%
%%
%% EOF SECTION EXPANDABLE EXTRACTION OF FIRST ITEM OF COMMA-LIST. 
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION EXPANDABLE ITERATION ON LIST OF LABELS
%%
%%  - REQUIRES SECTION PARAPHERNALIA.
%%  - REQUIRES SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%  - REQUIRES SECTION EXPANDABLE EXTRACTION OF FIRST ITEM OF COMMA-LIST.
%% 
%% \eqsRef{<comma-list>}%
%%
%% If <comma-list> contains only commas and/or space tokens, or is empty: 
%%   yields nothing.
%%   !!! Be aware that there is no \@bsphack..\@esphack for this case.
%%   This implies that you will get two spaces in this case if 
%%   the call to \EQsref has both a leading and a trailing space,
%%   i.e., is, e.g., <space>\EQsref{, ,}<space>   !!!
%%
%% If <comma-list> contains one item: 
%%   yields: Eq~(\ref{<item of comma-list>})
%%
%% If <comma-list> contains k items; k > 1: 
%%   yields:
%%     Eq~(\ref{<item 1 of comma-list>}%
%%         , \ref{<item 2 of comma-list>}%
%%         [...]%
%%         , \ref{<item k of comma-list>})%
%%
%% Due to \romannumeral0-expansion, the result will be delivered after two
%% expansion-steps/after having \eqsRef "hit" via two \expandafter(-chains).
%%
\newcommand\eqsRef[1]{%
  \romannumeral\UD@eqsRefiterator{}{#1,}%
}%
%% \UD@eqsRefiterator: #1 -- \ref-calls constructed so far
%%                     #2 -- (remaining) comma-list of labels
%%
\newcommand\UD@eqsRefiterator[2]{%
  \UD@CheckWhetherNull{#2}{%
     \UD@CheckWhetherBlank{#1}{0 }{%
       \expandafter\UD@CheckWhetherNull
       \expandafter{\UD@gobbletocomma#1,}{0 Eq}{0 Eqs}.~(#1)%
     }%
  }{%
    \expandafter\UD@Exchange\expandafter{%
       \expandafter{\UD@gobbletocomma#2}%
    }{%
      \expandafter\UD@eqsRefiterator\expandafter{%
        \romannumeral0%
        \expandafter\expandafter\expandafter\UD@CheckWhetherNull
        \expandafter\expandafter\expandafter{%
          \UD@ExtractFirstCommaArg{\ref}{#2}%
        }{ #1}{%
          \expandafter\expandafter\expandafter\UD@Exchange
          \expandafter\expandafter\expandafter{%
            \UD@ExtractFirstCommaArg{\ref}{#2}%
          }{%
            \UD@CheckWhetherNull{#1}{ }{ #1, }%
          }%
        }%
      }%   
    }%
  }%
}%
%%
%% EOF SECTION EXPANDABLE ITERATION ON LIST OF LABELS
%%//////////////////////////////////////////////////////////////////////////////
\makeatother


\newcommand\TestGobbleToGT{}%
\long\def\TestGobbleToGT#1>{}%
\newcommand\Test[1]{%
  \expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter\test
  \expandafter\expandafter\expandafter{%
    #1%
  }%
  \texttt{\expandafter\TestGobbleToGT\meaning\test}%
  \par\noindent\hrulefill
}%

\begin{document}

\section*{testing \texttt{\string\UD@ExtractFirstCommaArg}}

\makeatletter

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{,A,B,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{,A,B,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{ {} ,A,B,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{ {} ,A,B,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{{},A,B,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{{},A,B,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{A,B,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{A,B,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{{AB},C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{{AB},C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{ {AB} ,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{ {AB} ,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{  AB  ,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{  AB  ,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{  {AB},C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{  {AB},C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{{AB}  ,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{{AB}  ,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{ { A, B } ,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{ { A, B } ,C,D,E}}%

\noindent\verb|\UD@ExtractFirstCommaArg{<Action>}{ { {AB} } ,C,D,E}| yields:\\
\Test{\UD@ExtractFirstCommaArg{<Action>}{ { {AB} } ,C,D,E}}%

\makeatother

\newpage
\section*{testing \texttt{\string\eqsRef}}

\noindent\verb|\eqsRef{ A ,B, C,D ,,,E, F}| yields:\\
\Test{\eqsRef{ A ,B, C,D ,,,E, F}}%

\noindent
Be aware that it is possible to have one nameless referencing-label, \\
 i.e. \verb|\label{}| ..\verb|\ref{}|.\\
Here the last thing denotes the nameless label:\\
\verb|\eqsRef{ { A } ,B,C,{}}| yields:\\
\Test{\eqsRef{ { A } ,B,C,{}}}%

\noindent\verb|\eqsRef{ C}| yields:\\
\Test{\eqsRef{ C}}%

\noindent\verb|\eqsRef{ , }| yields:\\
\Test{\eqsRef{ , }}%

\noindent\verb|\eqsRef{  }| yields:\\
\Test{\eqsRef{  }}%

\noindent\verb|\eqsRef{}| yields:\\
\Test{\eqsRef{}}%

\end{document}

enter image description here enter image description here

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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