Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
    
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
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 :) –  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

2 Answers 2

up vote 9 down vote accepted

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

share|improve this answer
    
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}
share|improve this answer
    
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.