Signal individual item in comma separated list received as an argument

expl3macrosxparse

I'd like to define a command, with xparse's \NewDocumentCommand, which receives a comma separated list as argument, but to be able to somehow signal that some items on that list should be treated specially.

My first thought for this was to use bracing. And I came up with something like:

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand \mylist { > { \SplitList { , } } m }
  {
    \tl_map_inline:nn {#1}
      {
        \tl_if_head_is_group:nTF {##1}
          { Hi,~I'm~special~##1! \par }
          { ##1 \par }
      }
  }
\ExplSyntaxOff

\begin{document}

\mylist{item1,item2,{{item3}},item4,{{item5}},item6}

\end{document}

Which prints, as expected:

enter image description here

And, in case I cannot rely on the extra braces being just expanded away in typesetting, as with the example above, I could go with something like:

\cs_new:Npn \__my_tl_set_unbraced:Nn #1#2
  {
    \tl_if_head_is_group:nTF {#2}
      { \tl_set:Nn #1 #2 }
      { \tl_set:Nn #1 {#2} }
  }

after I've retrieved the "signal", and can then pass a variable set with this function as an argument for this to work as any other "non special" item on the list.

While this all works, and feels OK at first sight, I find it a little too "creative", to the point of getting weary, and got wondering if there are alternatives. Hence this question.

What I'd like to know is: is this a reasonable procedure? (from both the TeXnical and the user interface sides). Do you see any blatant caveats in it? Are there any good alternatives to it?

Best Answer

Your code is reasonable and works, but requires {{special item}}, because of TeX's rule that one pair of braces around arguments is stripped off when unbalanced token lists wouldn't arise.

I'd use |special item| that's simpler to type and avoid \SplitList: you need to go to the expl3 level anyway.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand \mylist { m }
  {
    \gusbrs_mylist:n { #1 }
  }

\cs_new_protected:Nn \gusbrs_mylist:n
  {
    \clist_map_inline:nn {#1}
      {
        \str_if_eq:eeTF { \tl_head:n { ##1 } } { | }
          { \__gusbrs_mylist_special:w ##1 }
          { ##1 \par }
      }
  }

\cs_new:Npn \__gusbrs_mylist_special:w | #1 |
  {
    Hi,~I'm~special~#1! \par
  }
\ExplSyntaxOff

\begin{document}

\mylist{item1,item2,|item3|,item4,|item5|,item6}

\end{document}

As an exercise, you can add a test for the trailing | before calling the :w function and raise a warning or error.

enter image description here

After reading comments, you can also signal the special items with just a prefix character, here |.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand \mylist { m }
  {
    \gusbrs_mylist:n { #1 }
  }

\cs_new_protected:Nn \gusbrs_mylist:n
  {
    \clist_map_inline:nn {#1}
      {
        \str_if_eq:eeTF { \tl_head:n { ##1 } } { | }
          { \__gusbrs_mylist_special:e { \tl_tail:n { ##1 } } }
          { ##1 \par }
      }
  }

\cs_new:Nn \__gusbrs_mylist_special:n
  {
    Hi,~I'm~special~#1! \par
  }
\cs_generate_variant:Nn \__gusbrs_mylist_special:n { e }

\ExplSyntaxOff

\begin{document}

\mylist{item1,item2,|item3,item4,|item5,item6}

\end{document}
Related Question