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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.