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.

1

2 Answers 2

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.

3
  • 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, 2014 at 16:21
  • @Jörg That's a different thing, then. So you want just to print the items?
    – egreg
    Apr 14, 2014 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, 2014 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?.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .