4

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?

13
  • 1
    The problem with \tl_if_head_is_group:nTF for this case is that both {item3} and {i}tem3 will be true. Other than that, your code looks correct, but you have to be sure what syntax you want to impose on your users (assuming it's not just for personal use). I'd find using {{item}} a bit cumbersome. Aug 20, 2021 at 2:23
  • Hi @PhelypeOleinik, thanks for the comment. I hadn't thought of {i}tem3, indeed. I don't expect it to be a problem in the case, since I don't expect to get this kind of input. But well pointed. And, agreed, {{item}} is cumbersome. In a way it is the fact that I don't really like it that triggered me to ask... Do you know any good alternatives?
    – gusbrs
    Aug 20, 2021 at 2:28
  • It depends, I think, on what's the purpose of the list. You could use *item (since * is already ubiquitously used to mean “treat this differently”), but then you'd need extra gymnastics to actually add an item with a * in its name because it would be confused with the marker: you'll have this problem with any marker you choose. That's why it depends quite a bit on what the list contains. A safer bet is to write item1,\special{item2} for a good choice on the name of the macro \special (but then that's a lot to type, so not really good either). Aug 20, 2021 at 2:35
  • The list items are reference labels. I don't expect much trouble in the content, but I would not like to restrain user choice of characters. \special may be safer, but I think it is more cumbersome than the double bracing, to the user, and to handle in the implementation side (as far as I can tell).
    – gusbrs
    Aug 20, 2021 at 2:40
  • Well, once you choose the marker, you can write it like \str_if_eq:eeTF { \tl_head:n {##1} } { * } { Hi,~I'm~special~\use_none:n ##1! \par } { ##1 \par } Aug 20, 2021 at 2:46

2 Answers 2

4

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}
9
  • Hi, egreg, thank you! | is a good idea for a character here. I might even evade the exercise and demand only the leading one, it would not be a bad thing for the meaning I'm trying to convey. :-)
    – gusbrs
    Aug 20, 2021 at 10:00
  • If I recall correctly, you have the canonical here on the site on "characters allowed in labels" (tex.stackexchange.com/a/18312/105447). Theoretically, | is allowed for labels, isn't it? Have you ever seen people using it for this?
    – gusbrs
    Aug 20, 2021 at 10:03
  • @gusbrs No, never. You might want to use * as a single prefix for special items.
    – egreg
    Aug 20, 2021 at 10:19
  • That was Phelype's suggestion too. I'll think about the alternatives. This is a functionality I'd like to exist, but I believe should be used rarely. So, I'm a little divided whether to provide such an ad hoc syntax, or simply to receive the "special item" in the optional argument. That would involve repetition, but keep the syntax "clean". Anyway, I have to think this through. The technical problem is well sorted here. Thanks again!
    – gusbrs
    Aug 20, 2021 at 10:26
  • @gusbrs I added the code for | as a prefix.
    – egreg
    Aug 20, 2021 at 10:36
6

Here is a latex2e way, using listofitems. Special items contain a *, which should appear at the end of the item. The special character denoter can be changed by editing the last entry in the \setsepchar list.

\documentclass{article}
\usepackage{listofitems}
\newcommand\processmylist[1]{%
  \setsepchar{,/*}%
  \readlist*\mylist{#1}%
  \foreachitem\z\in\mylist[]{%
    \ifnum\listlen\mylist[\zcnt]=1
      \z
    \else
      SPECIAL: \mylist[\zcnt,1]%
    \fi
    \\
  }%
}
\begin{document}
\noindent\processmylist{item1, item2, item3*, item4, item 5*}
\end{document} 

enter image description here

4
  • Hi, Steven, thank you! I didn't know listofitems, I will check it out. But, for the use case, I think this is too small a task to add a dependency. I would like to handle this with the kernel, if possible.
    – gusbrs
    Aug 20, 2021 at 2:34
  • @gusbrs Understood. By the way, listofitems runs in plain TeX, as well with \input listofitems. Aug 20, 2021 at 2:49
  • I was just taking a look at the documentation, and it seems quite interesting. Thanks for pointing me to it.
    – gusbrs
    Aug 20, 2021 at 2:51
  • 1
    @gusbrs You are welcome. If you search this site for listofitems, you will also find a number of ways in which it can be applied. The nested parsing is quite powerful. Aug 20, 2021 at 3:23

You must log in to answer this question.

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