3

Why does the \test command not split the argument when called from a foreach loop?

\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{
    (#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}

\newcommand{\looptest}[1]{
   \foreach \n in {#1}{
       $\test{\n}$\\
    };

$\test{1|1}$\\       % this works
$\test{2|2|1}$\\     % this works
$\test{3|3|2|'}$\\   % this works
$\test{4|4|3|''}$\\  % this works

\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
2

The arguments are not expanded timely. Every foreach spin argument is still inside a brace pair. Also don't use whitespace inside the foreach arguments. It might cause pattern mismatches.

\documentclass{article}
\usepackage{pgffor,xparse}

\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{(#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}
\newcommand{\looptest}[1]{\foreach\n in{#1}{$\expandafter\test\expandafter{\n}$\\}}

\begin{document}\noindent
$\test{1|1}$\\       % this works
$\test{2|2|1}$\\     % this works
$\test{3|3|2|'}$\\   % this works
$\test{4|4|3|''}$\\  % this works
\looptest{1|2|1,3|7|2,6|7|3,6|5,9|5|3|''} % this does not
\end{document}

enter image description here

4

This uses a listofitems approach to parse the input to \looptest. The introductory \setsepchar{,} sets the parsing character as , . The macro \readlist*\looplist{#1} parses the list into a \looplist[<index>] array (while ignoring blank spaces around the , delimiters), which is then sequentially accessed with a \foreachitem loop. However, the loop argument \n must be expanded once on its way to being digested by \test.

\documentclass{article}
\usepackage{pgffor,xparse,listofitems}

\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{
    (#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}

\newcommand{\looptest}[1]{%
   \setsepchar{,}%
   \readlist*\looplist{#1}%
   \foreachitem \n \in \looplist{%
       $\expandafter\test\expandafter{\n}$\\
    }
}

\begin{document}\noindent
$\test{1|1}$\\       % this works
$\test{2|2|1}$\\     % this works
$\test{3|3|2|'}$\\   % this works
$\test{4|4|3|''}$\\  % this works

\noindent\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
\end{document}

enter image description here

And here is a way to totally eliminate pgffor and xparse, doing it completely within listofitems. Note that stray blank spaces may be introduced not only around the list commas , but also around the | separators, with no ill effect.

\documentclass{article}
\usepackage{listofitems}
\makeatletter
\newcommand\test[1]{%
  \setsepchar{{|}}%
  \readlist*\testlist{#1}%
  \def\temp{\printtest}%
  \foreachitem\testitem\in\testlist{%
    \expandafter\g@addto@macro\expandafter\temp\expandafter{\expandafter{\testitem}}%
  }%
  \temp\relax\relax\relax%
}
\makeatother
\newcommand\printtest[4]{(#1,#2)\quad s_{#3}#4}
\newcommand{\looptest}[1]{%
   \setsepchar{,}%
   \readlist*\looplist{#1}%
   \foreachitem \n \in \looplist{%
       $\expandafter\test\expandafter{\n}$\\
    }%
}
\begin{document}\noindent
$\test{1|1}$\\       % this works
$\test{2|2|1}$\\     % this works
$\test{3|3|2|'}$\\   % this works
$\test{4|4|3|''}$\\  % this works

\noindent\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
\end{document}

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.