1

I'm writing a class where I have an arbitrary number of strings that I'd like to concatenate, then loop over and typeset using \ForEachX from the forarray package. If I define a command to add to a string, something like:

\newcommand{\addtostring}[1]{\expandafter\def\expandafter\teststring\expandafter{\teststring {, }#1}}
\addtostring{A string}
\addtostring{to break}

And then try to break on comma, \ForEachX doesn't seem to recognise the commas to break on.

If instead, I define a command containing a similar string, there's no problem (see the MWE below). I suspect this has something to do with the \expandafter commands, but my understanding of how this command works is pretty fuzzy.

How can I set this up so that my \addtostring command allows an arbitrary number of comma-separated tokens to be strung together into something I can split on the comma with \ForEachX?

Here's the MWE:

\documentclass[10pt,a4paper]{article}
\usepackage{forarray}

\newcommand{\teststring}{}
\newcommand{\addtostring}[1]{\expandafter\def\expandafter\teststring\expandafter{\teststring {, }#1}}
\addtostring{A string}
\addtostring{to break}

\newcommand{\anotherteststring}{, Another string, to break}

\begin{document}

 Test string: \teststring

 \begin{itemize}
  \ForEachX{,}{\item \thislevelitem}{\teststring}
  \ForEachX{,}{\item \thislevelitem}{\anotherteststring}
 \end{itemize}

\end{document}

I know this example is a bit artificial. \addtostring is a stub for a command that takes two arguments and produces a formatted string with them.

Also, I'm aware that the way I have this code set up I'll have an extra empty token at the start of the string. I can deal with that.

0

Remove the braces around the comma:

\documentclass[10pt,a4paper]{article}
\usepackage{forarray}

\newcommand{\teststring}{}
\newcommand{\addtostring}[1]{%
  \expandafter\def\expandafter\teststring\expandafter{\teststring,#1}%
}
\addtostring{A string}
\addtostring{to break}

\newcommand{\anotherteststring}{, Another string, to break}

\begin{document}

 Test string: \teststring

 \begin{itemize}
  \ForEachX{,}{\item \thislevelitem}{\teststring}
  \ForEachX{,}{\item \thislevelitem}{\anotherteststring}
 \end{itemize}

\end{document}

enter image description here

A better implementation with expl3 that uses sequences. The optional argument to \addtostring is for a “string name” (by default the name is “default”). Similarly for the optional argument to \usestring. Note that this has no side effect with commas at the beginning.

\documentclass[10pt,a4paper]{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\addtostring}{O{default}m}
 {
  \seq_if_exist:cF { g_goblin_string_#1_seq }
   {
    \seq_new:c { g_goblin_string_#1_seq }
   }
  \seq_gput_right:cn { g_goblin_string_#1_seq } { #2 }
 }

\NewDocumentCommand{\usestring}{O{default}m}
 {
  \seq_map_inline:cn { g_goblin_string_#1_seq } { #2 ##1 }
 }
\ExplSyntaxOff

\addtostring{A string}
\addtostring{to break}

\addtostring[new]{Another string}
\addtostring[new]{to break}

\begin{document}

\begin{itemize}
\usestring{\item}
\usestring[new]{\item}
\end{itemize}

\end{document}

enter image description here

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.