8

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}

output

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?

3
  • Note: According to a chat discussion backed by texdoc expl3, it is correct to say \test:www rather than test:w. Commented Jun 17, 2014 at 20:09
  • 2
    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 :) Commented Jun 18, 2014 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 :) Commented Jun 18, 2014 at 18:24

2 Answers 2

9

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}

enter image description here


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
   }
   {
    BAD~DATE!
   }
 }
\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}

enter image description here

2
  • 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 :) Commented Jun 17, 2014 at 19:50
  • @SeanAllred No you can't; I added some words at the beginning.
    – egreg
    Commented Jun 17, 2014 at 19:51
6

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}
3
  • 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). Commented Jun 17, 2014 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. Commented Jun 17, 2014 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. Commented Jun 17, 2014 at 20:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .