9

Using receipt of "LaTeX3: unable to convert space separated list into clist" I elaborated the following code for my needs:

\documentclass{book}
 ...
\usepackage{expl3}

\begin{document}

\newcommand{\PrintAnswer}[1]{%
\InputIfFileExists{#1}{\refstepcounter{subsection}}{\typeout{*** #1 not found ***}}}

\ExplSyntaxOn
\cs_new:Nn\PrintAnswerList:n{
  \clist_set:Nx\l_csv_clist{#1}
  \clist_map_inline:Nn\l_csv_clist{
    \typeout{**** Printing ##1.ans}
    \ExplSyntaxOff
    \PrintAnswer{##1.ans}
    \ExplSyntaxOn
  }
}
\PrintAnswerList:n{\inputfiles}
\ExplSyntaxOff

\end{document} 

It is intended for conditional compilation of a textbook, every chapter of which (eg, 01.tex, 02.tex) writes answers to problems to the file named after the name of the chapter source file, (eg, 01.ans, 02.ans etc). Near the end of the book these files are read in by the macro \PrintAnswer. Usually, I compile only few chapters using the following trick to keep desired chapters in \inputfiles macro:

\typein[\inputfiles]{^^JEnter filename(s) for \protect\includeonly:}

All that works fine, but I was forced to switch off experimental syntax before \PrintAnswer{##1.ans} because otherwise answer files are not processed correctly (in particular, LaTeX complains that the commands for greek letters are not defined and hyphenation is broken). Therefore my question is How can one rewrite the above code using user-level LaTeX3 commands? I found \SplitList command in xparse package. Can it help?

1 Answers1

9

In LaTeX3, the preferred way to get user-level functions is xparse and its \NewDocumentCommand function.

If the list was not a comma-separated list, then you would have to do something like

\ExplSyntaxOn
\NewDocumentCommand{\PrintAnswerList}{>{\SplitList;}m}
  { \tl_map_inline:nn {#1} { \PrintAnswer {##1.ans} } }
\ExplSyntaxOff
\PrintAnswerList { file01 ; file 02 ; file03 }

Then \PrintAnswer would be performed outside the scope of the expl syntax.

Here, your life is both slightly easier because you have a comma-separated list, and slightly harder because it is not given directly, but is given hidden inside a macro, \inputfiles. In the code below, I used \clist_map_inline:on, which expands its clist argument once before performing the second argument for each item. Since this particular variant is not available in the kernel, we need to provide it, with

\clist_generate_variant:Nn \clist_map_inline:nn { o }

All in all, you can do for instance (I changed \PrintAnswer too)

\documentclass{book}
 ...
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand { \PrintAnswer } { m }
  {
    \file_if_exist:nTF {#1}
      {
        \iow_term:n {****~Printing~#1}
        \file_input:n {#1}
        \refstepcounter {subsection}
      }
      { \iow_term:n {****~#1~not~found~****} }
  }
\cs_generate_variant:Nn \clist_map_inline:nn {o}
\NewDocumentCommand { \PrintAnswerList } { m }
  { \clist_map_inline:on {#1} { \PrintAnswer {##1.ans} } }
\ExplSyntaxOff

\begin{document}

\PrintAnswerList{\inputfiles}

\end{document}
  • Why not just use \clist_map_inline:Nn (as we are looking here at a stored clist)? – Joseph Wright Jan 04 '12 at 14:58
  • 1
    @JosephWright I should probably have explained that too. I don't know if the OP's clist has spurious spaces or not. \clist_map_inline:nn strips spaces, while \clist_map_inline:Nn assumes that it gets a "true clist", and it does not strip any space, for efficiency. – Bruno Le Floch Jan 04 '12 at 15:32
  • @BrunoLeFloch: Is \clist_map_inline:on supposed to be \clist_map_inline:nn (nn instead of on) as I get Undefined control sequence. with on. For me the nn treats the comma separated list as one item. If I switch to Nn then it separates the list items, but that does not remove the spurious spaces!! – Peter Grill Apr 19 '12 at 23:00
  • @PeterGrill: sorry for the long delay (I'm busy elsewhere). The line \cs_generate_variant:Nn \clist_map_inline:nn { o } generates the variant of \clist_map_inline:nn with argument specifier :on. This variant (which happens not to be defined by default) expands its first argumnet once. – Bruno Le Floch May 06 '12 at 09:18
  • @BrunoLeFloch: How to modify this code to sort the list of files in assending or dessending order? – Igor Kotelnikov Jan 19 '16 at 05:43
  • @IgorKotelnikov That's not trivial. You'd have to change the implementation of \PrintAnswerList to include sorting, which can be done using l3sort. I don't remember the exact syntax of l3sort, but presumably one has to store #1 in a clist variable \l_answers_clist then do \clist_sort:Nn \l_answers_clist { ... your comparison using ##1 and ##2 ... { \sort_ordered: } { \sort_reversed: } }. Maybe you should ask a separate question, specifying what sorting you want exactly. – Bruno Le Floch Jan 19 '16 at 16:10