3

The expl3 package provides \tl_put_right which enables us to append tokens to the right side of the current content of a token list variable:

\documentclass{article}
\usepackage{xparse}

\begin{document}
\ExplSyntaxOn

\tl_new:N \foo
\tl_set:Nn \foo {bar}

\begin{description}
\item[Before:]
  \foo
\item[Put right:]
  \tl_put_right:Nn \foo {s}
  \foo
\end{description}

\ExplSyntaxOff
\end{document}

But I'm missing a \tl_pop_right similar command (which does exist for sequences: \seq_pop_right).

Edit: What I have in mind for the command \tl_pop_right is to pop the content of the token list given in its argument: if \l_tmpa_tl contains "baz", \tl_pop_right:n {\l_tmpa_tl} should leave "ba" in the input stream.

4
  • I'm not sure if this would make sense. The normal argument of \tl-commands are tokens in plural, not one token. Oct 12, 2018 at 13:31
  • @UlrikeFischer I'm not sure to understand your comment. I'll edit my question in order to be more explicit. Oct 12, 2018 at 13:35
  • I mean your commands are not symmetric. ` \tl_put_right:Nn \foo {ssssss}` adds 6 s to \foo. What do you expect \tl_pop_right to do? Oct 12, 2018 at 13:37
  • @UlrikeFischer Indeed, they are not symmetric. I'm looking for the equivalent of the pop method of lists in Python (see my edit). Oct 12, 2018 at 13:48

1 Answer 1

2

There is an even more powerful operation, namely \tl_range:Nnn.

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn

\cs_new:Nn \db_tl_pop_left:NN
 {
  \tl_set:Nx #2 { \tl_range:Nnn #1 { 1 } { 1 } }
  \tl_set:Nx #1 { \tl_range:Nnn #1 { 2 } { \tl_count:N #1 } }
 }
\cs_new:Nn \db_tl_pop_right:NN
 {
  \tl_set:Nx #2 { \tl_range:Nnn #1 { -1 } { -1 } }
  \tl_set:Nx #1 { \tl_range:Nnn #1 { 1 } { \tl_count:N #1 - 1 } }
 }

\tl_set:Nn \l_tmpa_tl {{ab}cdef}

\db_tl_pop_right:NN \l_tmpa_tl \l_tmpb_tl

\tl_show:N \l_tmpa_tl
\tl_show:N \l_tmpb_tl

\db_tl_pop_left:NN \l_tmpa_tl \l_tmpb_tl

\tl_show:N \l_tmpa_tl
\tl_show:N \l_tmpb_tl

\stop

The output on the console is

> \l_tmpa_tl={ab}cde.
<recently read> }

l.21 \tl_show:N \l_tmpa_tl

? 
> \l_tmpb_tl=f.
<recently read> }

l.22 \tl_show:N \l_tmpb_tl

? 
> \l_tmpa_tl=cde.
<recently read> }

l.26 \tl_show:N \l_tmpa_tl

? 
> \l_tmpb_tl={ab}.
<recently read> }

l.27 \tl_show:N \l_tmpb_tl

Your simpler function could be implemented as

\cs_new:Nn \db_tl_lastitem:n
 {
  \tl_range:nnn { #1 } { -1 } { -1 }
 }

Full example

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \db_tl_lastitem:n
 {
  \tl_range:nnn { #1 } { -1 } { -1 }
 }

\NewExpandableDocumentCommand{\lastitem}{m}
 {
  \db_tl_lastitem:n { #1 }
 }

\ExplSyntaxOff

\begin{document}

\lastitem{abcdef}

\lastitem{abcd{ef}}

\end{document}

enter image description here

If you want to throw away the last item:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \db_tl_nolastitem:n
 {
  \tl_range:nnn { #1 } { 1 } { \tl_count:n { #1 } - 1 }
 }

\NewExpandableDocumentCommand{\nolastitem}{m}
 {
  \db_tl_nolastitem:n { #1 }
 }

\ExplSyntaxOff

\begin{document}

\nolastitem{abcdef}

\nolastitem{abcd{ef}}

\end{document}

enter image description here

The fact that \tl_range:nnn and \tl_range:Nnn are in the “candidates” should not be of a concern: the functions are useful and they should stay. Perhaps the name could change.

With “non candidates”:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \db_tl_nolastitem:n
 {
  \tl_reverse:f
   {
    \tl_tail:f
     {
      \tl_reverse:n { #1 }
     }
   }
 }
\cs_generate_variant:Nn \tl_tail:n { f }
\cs_generate_variant:Nn \tl_reverse:n { f }

\NewExpandableDocumentCommand{\nolastitem}{m}
 {
  \db_tl_nolastitem:n { #1 }
 }

\ExplSyntaxOff

\begin{document}

\nolastitem{abcdef}

\nolastitem{abcd{ef}}

\end{document}
4
  • In fact I don't want to get the last item, but to remove it. Oct 12, 2018 at 13:51
  • @DenisBitouzé Easy enough. ;-)
    – egreg
    Oct 12, 2018 at 14:02
  • I knew it couldn't be difficult, especially for you, but warned you about my initial request in order to accept your answer :) BTW, is it safe to rely on tl_range which is currently in l3candidates? Oct 12, 2018 at 14:07
  • 1
    @DenisBitouzé I added an implementation with \tl_tail:n and \tl_reverse:n
    – egreg
    Oct 12, 2018 at 14:13

You must log in to answer this question.

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