\@for does not compose with \StrSubstitute

I want to split a space-delimited string into parts and generate code for each part. Apparently TeX works with comma-delimited strings natively so I tried writing an adaptation

\usepackage{xstring}
\makeatletter
\@for\next:=foo,bar,baz\do{X \next Y} \\
\StrSubstitute{foo bar baz}{ }{,} \\
\@for\next:=\StrSubstitute{foo bar baz}{ }{,}\do{X \next Y}
\makeatother


The first line of output for a comma-delimited string is correct. The second line of output showing a space-delimited-string being transformed into the corresponding comma-delimited string is correct.

However, in the third line, the second \@for, the string isn't being split.

Why not and how do I fix this?

• Most likely StrSubstitute is not expandable – user31729 Jan 18 '17 at 13:02
• tex doesn't have built in support for comma or space delimited strings (or really any notion of string at all) it will be doing as much work looping through your input changing spaces to commas so that you can iterate over commas as it would have done had you simply looped through spaces to start with, and then you still have to loop through the comma list. – David Carlisle Jan 18 '17 at 13:42

\StrSubstitute has multiple optional arguments and can't be expandable, so it is not possible to use the output from \StrSubstitute and feed it again into TeX's input stream.

It is possible to store the result of \StrSubstitute to a temporary macro and use this macro as input to \@for\next....

\documentclass{article}

\usepackage{xstring}

\begin{document}
\makeatletter
\@for\next:=foo,bar,baz\do{X \next Y} \\
\StrSubstitute{foo bar baz}{ }{,} \\
\StrSubstitute{foo bar baz}{ }{,}[\@stuff]
\@for\next:=\@stuff\do{X \next Y}
\makeatother
\end{document}


• Other possibility: Use expl3 and a \tl_replace.... macro – user31729 Jan 18 '17 at 13:11
• Much better: \seq_set_split:Nnn and then \seq_map_inline:Nn or \seq_map_function:NN – egreg Jan 18 '17 at 13:25
• @egreg: I know, but I don't have time right now. – user31729 Jan 18 '17 at 13:27

If the requirement is to loop through a space separated list there is no need to replace spaces by commas and loop through a comma separated list. Implementing that replace already probably requires the ability to iterate over the spaces.

For example this iterates over the space separated words putting each in an fbox.

\documentclass{article}

\def\zz#1{\zzz#1 \! }

\def\zzz#1 {\ifx\!#1\else\fbox{#1} \expandafter\zzz\fi}
\begin{document}

\zz{foo bar baz}

\end{document}


The listofitems package can parse, based on a specified multiplicity of characters, here given as a space and comma ,. Thus, one definition of \setsepchar solves all cases, without the use of xstring. EDITED to embody solution in the macro \processlist.

\documentclass{scrartcl}
\usepackage{listofitems}
\setsepchar{ ||,}%
\newcommand\processlist[1]{%