# \def\foo#1:#2:#3 can be called with \foo{a:b:c} but not \foo{a:\bc}

This works:

\def\myfunc#1{\expandafter\myfuncdoit#1\relax}
\def\myfuncdoit#1:#2:#3\relax{ First: (#1), Second: (#2), Third (#3) }

\foreach \p in {x:foo:int,y:bar:float,z:baz:bool}{ (\myfunc{\p}) }


It produces

First: (x), Second: (foo), Third (int) First: (y), Second: (bar), Third (float) First: (z), Second: (baz), Third (bool)

However, I need to invoke this \foreach over a list of pairs, with a shared first string:

\foreach \p in {foo:int,bar:float,baz:bool}{ (\myfunc{abc:\p}) }


I expected this to produce

First: (abc), Second: (foo), Third (int) First: (abc), Second: (bar), Third (float) First: (abc), Second: (baz), Third (bool)

but it doesn't compile

Runaway argument?
float,baz:bool, \pgffor@stop ,
Paragraph ended before \myfuncdoit was complete.
\par


Why doesn't it work and how do I fix it? Thanks.

• You need to expand the argument, otherwise \myfuncdoit sees abc:\p and doesn't see the second : delimiter. – Manuel Mar 9 '17 at 10:29
• It does not work because \p is not expanded before it is passed to \myfuncdoit, only the first token of #1 is expanded (the a of abc). If the argument is fully expandable you could use \edef\reserved@a{#1}\expandafter\myfuncdoit\reserved@a\relax. But I cannot test this, because unfortunately you have not posted a MWE. – Schweinebacke Mar 9 '17 at 10:31

You have to make sure that at the point where the arguments of \myfuncdoit are scanned, all separators are in place. No expansion takes place at this moment.

You can do it like that.

\newcommand\myfuncx[2]{\myfuncdoit#2:#1\relax}

\foreach \p in {foo:int,bar:float,baz:bool}
{ (\expandafter\myfuncx\expandafter{\p}{abc}) }


\documentclass{article}
\usepackage{pgffor}
\newcommand\myfuncx[2]{\myfuncdoit#2:#1\relax}
\def\myfuncdoit#1:#2:#3\relax{ First: (#1), Second: (#2), Third (#3) }
\begin{document}
\foreach \p in {foo:int,bar:float,baz:bool}
{ (\expandafter\myfuncx\expandafter{\p}{abc}) }
\end{document}

• I accepted this answer because it is more concise and requires no libraries, but it bothers me that {abc} comes after {\p} -- not that it matters except when I tried to adjust your solution so that {abc} is the first argument, it wouldn't compile. Am I just being thick or is there a reason you switched the order around? – spraff Mar 9 '17 at 15:41
• @spraff The point is that I want to expand \p before expanding \myfuncx. \expandafter tells TeX to expand the second next token before expanding the next one. So \expandafter\xxx\expandafter{\yyy will expand first \yyy and only then \xxx followed by { followed by whatever resulted from the expansion of \yyy. If I switch the order resulting in something like \xxx{abc}{\yyy}, then I cannot reach \yyy with \expandafters anymore. – gernot Mar 9 '17 at 15:48

An easy extension of my previous answer:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\myfuncthree}{>{\SplitArgument{2}{:}}m}{%
\myfuncsplitthree#1%
}
\NewDocumentCommand{\myfuncsplitthree}{mmm}{%
First: (#1), Second: (#2), Third: (#3).%
}

\ExplSyntaxOn
\NewDocumentCommand{\cycle}{ m +m }
{
\clist_map_inline:nn { #1 } { #2 }
}
\ExplSyntaxOff

\begin{document}

\cycle{foo:int, bar:float, baz:bool}{\myfuncthree{abc:#1}\par}

\end{document}


\cycle{foo:int, bar:float, baz:bool}{\myfuncthree{#1:zzz}\par}


you get the expected result.

Here is a solution using \edef to expand the argument of \myfunc:

\documentclass{article}
\usepackage{pgffor}

\makeatletter
\def\myfunc#1{\edef\my@tmp{#1}\expandafter\myfuncdoit\my@tmp\relax}
\def\myfuncdoit#1:#2:#3\relax{ First: (#1), Second: (#2), Third (#3) }
\makeatother

\begin{document}
\foreach \p in {x:foo:int,y:bar:float,z:baz:bool}{ (\myfunc{\p})\par }
\foreach \p in {foo:int,bar:float,baz:bool}{ (\myfunc{abc:\p})\par }
\end{document}