2

(This question is somehow related to this answer.)

I want to create a document command with an arbitrary number of (comma separated) parameters, each of them being a comma list, the items of which having to be processed.

The following MCE:

\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand\signature{m}
 {
  \__mymodule_process_list:n {#1}
 }
\seq_new:N \l__mymodule_items_seq
\cs_new_protected:Npn \__mymodule_process_list:n #1
{
  \seq_clear:N \l__mymodule_items_seq
  \seq_set_from_clist:Nn \l_tmpa_seq {#1}
  \seq_map_inline:Nn \l_tmpa_seq {
    \seq_set_from_clist:Nn \l_tmpb_seq {##1}
    \seq_get_right:NN \l_tmpb_seq \l_tmpa_tl
    \seq_get_left:NN \l_tmpb_seq \l_tmpb_tl
    \seq_put_right:Nx \l__mymodule_items_seq {
    % \seq_put_right:NV \l__mymodule_items_seq {
      \l_tmpa_tl
      \c_space_tl \l_tmpb_tl
      % \c_space_tl \textsc{\l_tmpb_tl}
    }
  }
  \seq_use:Nn \l__mymodule_items_seq { ~ \& ~ }
}
\ExplSyntaxOff

\begin{document} \signature{ {Last1, First1} }

\signature{ {Last1, First1}, {Last2, First2} }

\signature{ {Last1, First1}, {Last2, First2}, {Last3, First3} } \end{document}

works well, that is, the result is:

First1 Last1
First1 Last1 & First2 Last2
First1 Last1 & First2 Last2 & First3 Last3

but, if I replace \c_space_tl \l_tmpb_tl by \c_space_tl \textsc{\l_tmpb_tl} in order to get the last names in small caps, LaTeX complains:

! Missing control sequence inserted.
 <inserted text>
\inaccessible ```

In this context, if I replace \seq_put_right:Nx by e.g. \seq_put_right:NV, the compilation goes smoothly, but the result isn't the expected one (same last name on each line):

First1 Lᴀꜱᴛ1
First1 Lᴀꜱᴛ2 & First2 Lᴀꜱᴛ2 
First1 Lᴀꜱᴛ3 & First2 Lᴀꜱᴛ3 & First3 Lᴀꜱᴛ3

With \seq_put_right:Nx and, instead of \textsc{\l_tmpb_tl}, {\scshape \l_tmpb_tl}, it works as expected but why doesn't it work with \textsc{\l_tmpb_tl}?

Denis Bitouzé
  • 9,652
  • 4
  • 27
  • 85

2 Answers2

1

You need to prevent the expansion of \textsc (or any other macro that should not expand) with \exp_not:N, so

\seq_put_right:Nx \l__mymodule_items_seq
  { \c_space_tl \exp_not:N \textsc { \l_tmpb_tl } }
%               ^^^^^^^^^^

Your usage of the NV variant is wrong. The V-type is supposed to take a single variable as argument, so this would be correct:

\seq_put_right:NV \l__mymodule_items_seq \l_tmpb_tl

this would be a slightly weird syntax (though not necessarily wrong):

\seq_put_right:NV \l__mymodule_items_seq { \l_tmpb_tl }

and this is completely off

\seq_put_right:NV \l__mymodule_items_seq { \l_tmpa_tl \l_tmpb_tl }

\scshape works (after \begin{document}) because it is defined with \protected. If you do \ShowCommand\scshape, you will see \scshape=\protected macro:->[...], so it does not expand in \edef (used by the x expansion in \seq_put_right:Nx).

\textsc, on the other hand, is a robust macro (\ShowCommand\textsc):

> \textsc=robust macro:
->\protect \textsc  .

> \textsc =\long macro: #1->[...]

so it breaks inside an \edef (it would need \protected@edef to not explode).

1

You can use \exp_not:N \textsc, but tokens in the names could bomb as well. I suggest wrapping with \text_expand:n the parts were textual input might contain dangerous tokens.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand\signature{m} { __mymodule_process_list:n {#1} }

\seq_new:N \l__mymodule_items_seq

\cs_new_protected:Npn __mymodule_process_list:n #1 { \seq_clear:N \l__mymodule_items_seq \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_map_inline:Nn \l_tmpa_seq { \seq_set_from_clist:Nn \l_tmpb_seq {##1} \seq_get_right:NN \l_tmpb_seq \l_tmpa_tl \seq_get_left:NN \l_tmpb_seq \l_tmpb_tl \seq_put_right:Nx \l__mymodule_items_seq { \text_expand:n { \l_tmpa_tl \c_space_tl \textsc { \l_tmpb_tl } } } } \seq_use:Nn \l__mymodule_items_seq { ~ &amp; ~ } } \ExplSyntaxOff

\begin{document} \signature{ {Last1, First1} }

\signature{ {Last1, First1}, {Last2, First2} }

\signature{ {Last1, First1}, {Last2, First2}, {La'st3, F'irst3} } \end{document}

enter image description here

egreg
  • 1,121,712
  • Tokens in the names seem to be harmless in case { \scshape \l_tmpb_tl } is used instead of \textsc { \l_tmpb_tl }, isn't it? – Denis Bitouzé Jun 04 '21 at 19:53