# How can I define a greedy macro?

I have a feeling this is a duplicate somewhere, but how can I ensure that TeX will keep scanning until \relax or something similar?

\documentclass{article}
\usepackage{xparse}

\pagestyle{empty}
\setlength\parindent{0pt}

\begin{document}

Plain:

\def\test#1/#2/#3{
year:#1   \newline
month:#2  \newline
day:#3    \newline
}
\test 01/02/03

\bigskip

Expl3:

\ExplSyntaxOn
\cs_new:Npn \test:w #1/#2/#3 {
year:#1   \newline
month:#2  \newline
day:#3    \newline
}

\test:w 01/02/03
\ExplSyntaxOff

\bigskip

Keys:

\ExplSyntaxOn
\keys_define:nn { test } {
date .code:n = { \test:w #1 },
title .code:n = { title: #1 \newline},
}

\keys_set:nn {test} { title = hello, date = 15/16/17, title = hi}
\ExplSyntaxOff
\end{document}


I realize that I could introduce some token—perhaps the quark \q_stop—to the l3keys .code:n usage to terminate it 'normally'. Is there a way to go about doing this without such an introduction?

-
Note: According to a chat discussion backed by texdoc expl3, it is correct to say \test:www rather than test:w. –  Sean Allred Jun 17 at 20:09
I don't know about ‘correct’ — in this particular case using \test:www 01/02/03 <whatever> sort of does imply that the three numbers match up with the three args, so it's probably a good idea. In other cases where you don't get this nice symmetry, just using w would be fine. I even started using q for ‘delimited by quark’ arguments, but the other team members didn't seem to like it :) –  Will Robertson Jun 18 at 8:07
@WillRobertson I for one think using q is a fine idea. The main point behind both of those argspecs, I think, is to encourage the reader to go back and RTFM :) –  Sean Allred Jun 18 at 18:24

An argument is either delimited or undelimited; in the latter case only the first token or braced group is taken as the argument. Your \test:w macro has an undelimited third argument; delimit also the third argument and add the final delimiter in the .code:n part.

\documentclass{article}
\usepackage{xparse}

\pagestyle{empty}
\setlength\parindent{0pt}

\begin{document}

\ExplSyntaxOn
\cs_new:Npn \test:www #1 / #2 / #3 \q_stop {
year:#1   \newline
month:#2  \newline
day:#3    \newline
}

\test:w 01/02/03 \q_stop
\ExplSyntaxOff

\bigskip

Keys:

\ExplSyntaxOn
\keys_define:nn { test } {
date .code:n = { \test:www #1 \q_stop },
title .code:n = { title: #1 \newline},
}

\keys_set:nn {test} { title = hello, date = 15/16/17, title = hi}
\ExplSyntaxOff
\end{document}


Possibly better code that doesn't use delimited arguments explicitly. Less efficient, perhaps, but clearer. You can add several checks that the date is legal; wrong input with \test:www would result in an unscrutable error.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{ m }
{
\keys_set:nn { sean/test } { #1 }
}

\cs_new:Npn \sean_test:nn #1 #2
{
\seq_set_split:Nnn \l__sean_date_seq { #1 } { #2 }
\int_compare:nTF { \seq_count:N \l__sean_date_seq == 3 }
{
year: ~\seq_item:Nn \l__sean_date_seq { 1 } \newline
month:~\seq_item:Nn \l__sean_date_seq { 2 } \newline
day:  ~\seq_item:Nn \l__sean_date_seq { 3 } \newline
}
{
}
}
\cs_generate_variant:Nn \sean_test:nn { V }

\keys_define:nn { sean/test }
{
date-delimiter .tl_set:N = \l_sean_date_delimiter_tl,
date-delimiter .initial:n = { / },
date .code:n = { \sean_test:Vn \l_sean_date_delimiter_tl { #1 } },
title .code:n = { title: ~ #1 \newline },
}
\ExplSyntaxOff

\setlength{\parindent}{0pt}
\pagestyle{empty}

\begin{document}

\test{ title = hello, date = 15/16/17, title = hi }

\bigskip

\test{ title = hi, date-delimiter = - , date = 01-02-03 }

\end{document}


-
Exactly what I ended up doing—this is the simplest way, but is there another that would work? (I'm perfectly okay using the quark solution—that's what it was meant for—but I'm curious :) –  Sean Allred Jun 17 at 19:50
@SeanAllred No you can't; I added some words at the beginning. –  egreg Jun 17 at 19:51
Thanks :) I will accept as soon as I am able. –  Sean Allred Jun 17 at 19:52

Not sure what you need, perhaps:

\documentclass{article}
\usepackage{xparse}

\pagestyle{empty}
\setlength\parindent{0pt}

\begin{document}

Plain:

\def\test#1/#2/#3 {
year:#1   \newline
month:#2  \newline
day:#3    \newline
}
\test 01/02/03

\bigskip

Expl3:

\ExplSyntaxOn
\cs_new:Npn \test:w #1/#2/#3~{
year:#1   \newline
month:#2  \newline
day:#3    \newline
}

\test:w 01/02/03~
\ExplSyntaxOff

\bigskip

Keys:

\ExplSyntaxOn
\keys_define:nn { test } {
date .code:n = { \test:w #1~ },
title .code:n = { title: #1 \newline},
}

\keys_set:nn {test} { title = hello, date = 15/16/17, title = hi}
\ExplSyntaxOff
\end{document}

-
Looking at egreg's answer, this is the general solution strategy (to delimit the argument) but note that quarks were introduced in expl3 for just this very purpose :) it doesn't need a space (even though we can both see that the space will never go to the input stream). –  Sean Allred Jun 17 at 19:55
@SeanAllred quarks predated expl3 (and latex2e for that matter:-) yes I used a space as that's the natural terminator for your non expl3 \test example as it just picks up the end of line. –  David Carlisle Jun 17 at 19:59
I had no idea—and yes, you're definitely right that a space is the natural terminator when we are talking plain TeX. –  Sean Allred Jun 17 at 20:02