Print

Print


Thank you Joseph for the quick bug fix. Let me propose the following
code for inclusion. The idea is similar to `\prg_new_map_functions`,
which defines a set of maps, some of which are expandable. Namely,

\tl_gset_replacer:nnn {<name>} {<item1>} {<item2>}

defines expandable replacement functions:

\<name>_replace_aux:nwwn
\<name>_replace_some:nn
\<name>_replace_one:n
\<name>_replace_all:n

which are all `f`-expandable. Usage: `\<name>_replace_some:nn {<int>}
{<tl>}` will replace the <int> first occurences of <item1> by <item2>
in <tl> (this happens in two steps). The `_all` version replaces all
occurences, and the `_one` version replaces only the first occurence
(both do that in three steps).

The code follows. Sorry that it is made a bit obscure to avoid losing braces.

\cs_new:Npn \quark_use_none_from_mark_to_stop:w #1 \q_mark #2 \q_stop {#1}
\cs_new_eq:NN \_tl_storage:n \use:n
\cs_new:Npn \_tl_store:n #1 #2 \_tl_storage:n #3 {
  #2 \_tl_storage:n {#3#1}
}

\cs_new:Npn \tl_gset_replacer_aux:Nnn #1 #2 #3 {
  \cs_gset:Npn #1 ##1 ##2 #2 ##3 \_tl_storage:n {
    \tl_if_empty:nTF {##3} { %if end, stop.
      \exp_after:wN \_tl_store:n \exp_after:wN {##2\q_stop}
      \_tl_storage:n
    } {
      \int_compare:nNnTF {##1}={0} { %if 0, stop.
        \exp_after:wN \_tl_store:n \exp_after:wN {##2 #2 ##3\q_stop}
        \_tl_storage:n
      }{
        \exp_after:wN \_tl_store:n \exp_after:wN {##2 #3}
        \exp_after:wN #1 \exp_after:wN {
          \tex_number:D \etex_numexpr:D ##1-1 \tex_relax:D }
        \c_empty_tl ##3 \_tl_storage:n
      }
    }
  }
}
\cs_generate_variant:Nn \tl_gset_replacer_aux:Nnn {cnn}

\cs_new:Npn \tl_gset_replacer:nnn #1 #2 #3 {
  \cs_gset:cpx {#1_replace_one:n} {\exp_not:c{#1_replace_some:nn} {1}}
  \cs_gset:cpx {#1_replace_all:n} {\exp_not:c{#1_replace_some:nn} {-1}}
  \cs_gset:cpn {#1_replace_some:nn} ##1 ##2 {
    \tex_romannumeral:D 0
    \use:c {#1_replace_aux:nwwn} {##1}
    \c_empty_tl ##2
    \q_mark #2
    \_tl_storage:n{\quark_use_none_from_mark_to_stop:w \exp_stop_f:}
  }
  \tl_gset_replacer_aux:cnn {#1_replace_aux:nwwn} {#2} {#3}
}