4

I'm trying to generate a comma separated list that uses strings that may or may not be empty. For example \mylist{\stringA,\stringB,\stringC} would expand to A, C if B is empty or B, C if A is empty, etc.

In case it matters, the strings are generated with xstring, for example something like \StrBetween[3,4]{\longstring}{text:}{,}[\stringC] which may or may not be empty depending on whether the condition is met.

I'm pretty sure that I saw something similar somewhere, some time, but I just can't find it.

4

This might be done with pure expansion, but since you're using xstring it's not really necessary:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\mylist}{ m o }
 {
  \clist_clear:N \l_tmpa_clist
  \clist_map_inline:nn { #1 }
   {
    \clist_put_right:No \l_tmpa_clist { ##1 }
   }
  \IfNoValueTF{#2}
   { \l_tmpa_clist }
   { \clist_set_eq:NN #2 \l_tmpa_clist }
 }
\ExplSyntaxOff

\newcommand\stringA{A}
\newcommand\stringB{}
\newcommand\stringC{C}

\begin{document}

\mylist{\stringA,\stringB,\stringC}

\mylist{\stringA,\stringB,\stringC}[\listA]

\show\listA


\end{document}

The \show\listA command produces

> \listA=macro:
->A,C.

Without an optional argument the result will be simply printed.


If you want to print the resulting list with a space following the comma, then a different approach is needed:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\mylist}{ m }
 {
  \seq_clear:N \l_tmpa_seq
  \clist_map_inline:nn { #1 }
   {
    \tl_if_empty:oF { ##1 } { \seq_put_right:No \l_tmpa_seq { ##1 } }
   }
  \seq_use:Nn \l_tmpa_seq {,~}
 }
\ExplSyntaxOff

\newcommand\stringA{A}
\newcommand\stringB{}
\newcommand\stringC{C}

\begin{document}

\mylist{\stringA,\stringB,\stringC}


\end{document}

In case you want to avoid that \newcommand{\stringB}{ } prints a space, use \tl_if_blank:oF instead of \tl_if_empty:oF.

  • Thanks. Can you help me altering the code so as to not ignore white spaces in the list? I would like A, C. – Jörg Apr 14 '14 at 16:21
  • @Jörg That's a different thing, then. So you want just to print the items? – egreg Apr 14 '14 at 16:22
  • Well, yes. Printing the items and the respective commas. Your solution is great - I like the \show\listA, but just with an extra whitespace between items. – Jörg Apr 14 '14 at 16:24
3

Try the following:

enter image description here

\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\def\ifemptyarg#1{% https://tex.stackexchange.com/a/58638/5764
  \if\relax\detokenize{#1}\relax % H. Oberdiek
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\makeatother
\providecommand{\listcomma}{}
\newcommand{\mylist}[2][,]{%
  \renewcommand{\listcomma}{\renewcommand{\listcomma}{#1}}% https://tex.stackexchange.com/a/89187/5764
  \renewcommand*{\do}[1]{% How to process each item
    \expandafter\ifemptyarg\expandafter{##1}
      {}% Do nothing
      {\unskip\listcomma{} \penalty0 ##1}% Print <,> <space> <item>
    }%
    \docsvlist{#2}% Process list
}
\begin{document}
\def\strA{strA}
\def\strB{strB}
\def\strC{}
\def\strD{strD}
\mylist{\strA,\strB,\strC,\strD}
\end{document}

The process above uses one of the options specified in How to iterate over a comma separated list?.

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.