expl 3 - 有没有一个好的方法可以弹出列表中的所有项目并对其采取行动?

expl 3 - 有没有一个好的方法可以弹出列表中的所有项目并对其采取行动?

以下是我对表格类内容的操作方式。我想知道是否有比\bool_while_do我使用的方法更好的方法?

以下 MWE 是我被要求做的起点这个帖子(从我的角度来看最困难的事情已经完成了)。

\documentclass{article}

% Sources
%   * https://tex.stackexchange.com/a/475291/6880
%   * https://tex.stackexchange.com/a/558343/6880

\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \l__tnscalc_splittab_seq
\seq_new:N \l__tnscalc_subseq_seq
\int_new:N \l__tnscalc_nbline_int
\int_new:N \l__tnscalc_numcol_int
\tl_new:N \l__tnscalc_xline_temp_tl
\tl_new:N \l__tnscalc_pline_temp_tl

% #1 : line separator
% #2 : cell separator
% #3 : content
\NewDocumentCommand{\splittab}{m m +m}
 {
  \tnscalc_splittab:nnn{#1}{#2}{#3}
 }

% The internal version of the general purpose macro
\cs_new_protected:Nn \tnscalc_splittab:nnn
 {
  % #1 : line separator
  % #2 : cell separator
  % #3 : content
  % A group allows nesting
  \group_begin:
  % Split into parts
  \seq_set_split:Nnn \l__tnscalc_splittab_seq { #1 } { #3 }

  \int_set:Nn \l__tnscalc_nbline_int { \seq_count:N \l__tnscalc_splittab_seq } % why?
  
  % First column
  \seq_pop_left:NN \l__tnscalc_splittab_seq \l__tnscalc_xline_temp_tl
  \seq_set_split:NnV \l__tnscalc_x_seq { #2 } \l__tnscalc_xline_temp_tl

  \seq_pop_left:NN \l__tnscalc_splittab_seq \l__tnscalc_pline_temp_tl
  \seq_set_split:NnV \l__tnscalc_p_seq { #2 } \l__tnscalc_pline_temp_tl
  
  \int_set:Nn \l__tnscalc_numcol_int { \seq_count:N \l__tnscalc_x_seq }
  
  % Pop the column by column.
  \bool_while_do:nn { \int_compare_p:nNn \l__tnscalc_numcol_int > 0 }{
    \seq_pop_left:NN \l__tnscalc_x_seq \l__tnscalc_x_tl
    \seq_pop_left:NN \l__tnscalc_p_seq \l__tnscalc_y_tl
  
    (\int_use:N \l__tnscalc_numcol_int :: \l__tnscalc_x_tl ; \l__tnscalc_y_tl)
  
    \int_add:Nn \l__tnscalc_numcol_int {-1}
  }
  \group_end:
 } 
\ExplSyntaxOff


\begin{document}

\splittab{\\}{&}{ a & b & c \\ 1 & 2 & 3}

\end{document}

答案1

如果你没有固定数量的项目需要处理,那么这会有点棘手,但当然是可行的。\tnscalc_splittab:nnn下面的实现将把序列拆分两次,第一次在第一个分隔符处,第二次在第二个分隔符处,然后将其重组为:

\__tnscalc_item:nw {a}{b}{c}\q_recursion_tail
\__tnscalc_item:nw {1}{2}{3}\q_recursion_tail
\__tnscalc_item:nw {\q_nil }\q_stop \q_recursion_stop

然后 every\__tnscalc_item:nw会收集它后面的项目(结束标记 除外)\q_nil,并将收集的项目传递给\__tnscalc_do:n。经过几个扩展步骤后,您将获得:

\__tnscalc_do:n {{a}{1}}
\__tnscalc_item:nw {b}{c}\q_recursion_tail
\__tnscalc_item:nw {2}{3}\q_recursion_tail
\__tnscalc_item:nw {\q_nil }\q_stop \q_recursion_stop

删除第一批项目。再删除一些项目后,您将获得:

\__tnscalc_do:n {{a}{1}} % already executed
\__tnscalc_do:n {{b}{2}}
\__tnscalc_item:nw {c}\q_recursion_tail
\__tnscalc_item:nw {3}\q_recursion_tail
\__tnscalc_item:nw {\q_nil }\q_stop \q_recursion_stop

然后将使用最后一批,\q_recursion_tail标记将发出列表末尾的信号,您将获得:

\__tnscalc_do:n {{a}{1}} % already executed
\__tnscalc_do:n {{b}{2}} % already executed
\__tnscalc_do:n {{c}{3}} % already executed

由于项目数量是可变的,因此每列传递时都会\__tnscalc_do:n用括号括住所有项目,因此\__tnscalc_do:n您必须确定项目数量(\tl_count:n {#1}可能有帮助)并相应地处理它们。您还可以使用 映射到列中的每个项目\tl_map_inline:nn {#1} { <code with ##1> }

映射确保\__tnscalc_do:n始终接收相同数量的项目。任何不完整的列都会被忽略。

要获取代码的输出,您可以定义\__tnscalc_do:n为:

\cs_new_protected:Npn \__tnscalc_do:n #1
  {
    (\int_use:N \l__tnscalc_numcol_int :: \use_i:nn #1 ; \use_ii:nn #1 )
    \int_decr:N \l__tnscalc_numcol_int
  }

\use_i:nn(请注意,和的使用\use_ii:nn假定只有两个\\以 - 分隔的项目;如果数字不同,则不能再使用这两个!)

在此处输入图片描述

将的定义更改\__tnscalc_do:n为:

\cs_new_protected:Npn \__tnscalc_do:n #1
  {
    Column~\int_use:N \l__tnscalc_numcol_int :~
    \tl_map_inline:nn {#1}
      { (##1) }
    \par
    \int_decr:N \l__tnscalc_numcol_int
  }

对于相同的输入,产生:

在此处输入图片描述

\__tnscalc_do:n您可以对 做出参数的定义\splittab,但我将其留作练习。

代码如下:

\documentclass{article}
\RequirePackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand \splittab { m m +m }
  { \tnscalc_splittab:nnn {#1} {#2} {#3} }
% Variables
\int_new:N \l__tnscalc_numcol_int
\seq_new:N \l__tnscalc_tmp_seq
\tl_new:N \l__tnscalc_items_tl
% Main function
\cs_new_protected:Nn \tnscalc_splittab:nnn
  {
    \group_begin:
      \tl_clear:N \l__tnscalc_items_tl
      \int_set_eq:NN \l__tnscalc_numcol_int \c_max_int
      \seq_set_split:Nnn \l__tnscalc_tmp_seq {#1} {#3}
      \seq_map_inline:Nn \l__tnscalc_tmp_seq
        {
          \seq_set_split:Nnn \l__tnscalc_tmp_seq {#2} {##1}
          \__tnscalc_seq_set_map:NNn \l__tnscalc_tmp_seq
            \l__tnscalc_tmp_seq { {####1} }
          \int_set:Nn \l__tnscalc_numcol_int
            {
              \int_min:nn { \l__tnscalc_numcol_int }
                { \seq_count:N \l__tnscalc_tmp_seq }
            }
          \tl_put_right:Nx \l__tnscalc_items_tl
            {
              \exp_not:N \__tnscalc_item:nw
              \seq_use:Nn \l__tnscalc_tmp_seq { }
              \exp_not:N \q_recursion_tail
            }
        }
      \tl_put_right:Nn \l__tnscalc_items_tl
        { \__tnscalc_item:nw { \q_nil } \q_stop }
      \tl_use:N \l__tnscalc_items_tl \q_recursion_stop
    \group_end:
  }
\cs_new_protected:Npn \__tnscalc_item:nw
  { \__tnscalc_iterate_collect:nnw { } }
\cs_new_protected:Npn \__tnscalc_iterate_collect:nnw #1 #2
  {
    \quark_if_recursion_tail_stop:n {#2}
    \quark_if_nil:nTF {#2}
      { \__tnscalc_iterate_collect_end:nw {#1} }
      { \__tnscalc_iterate_collect_more:nw { #1{#2} } }
  }
\cs_new_protected:Npn \__tnscalc_iterate_collect_more:nw #1 #2
    \__tnscalc_item:nw #3 \q_stop
  { \__tnscalc_iterate_collect:nnw {#1} #3 \__tnscalc_item:nw #2 \q_stop }
\cs_new_protected:Npn \__tnscalc_iterate_collect_end:nw #1
    \__tnscalc_item:nw #2 \q_stop
  {
    \__tnscalc_do:n {#1}
    \__tnscalc_item:nw #2 \__tnscalc_item:nw { \q_nil } \q_stop
  }
% Compatibility for older expl3
\cs_if_exist:NTF \seq_set_map_x:NNn
  { \cs_new_eq:NN \__tnscalc_seq_set_map:NNn \seq_set_map:NNn } % newer expl3
  {
    \cs_new_protected:Npn \__tnscalc_seq_set_map:NNn #1 #2 #3
      { \seq_set_map:NNn #1 #2 { \exp_not:n {#3} } } % older expl3
  }
%
% In this macro, #1 will have as many items as
% there are \\-separated items in your list.
%
% You can iterate over those items with \tl_map_inline:nn
% or you can have some other macro process them.
\cs_new_protected:Npn \__tnscalc_do:n #1
  {
    (\int_use:N \l__tnscalc_numcol_int :: \use_i:nn #1 ; \use_ii:nn #1 )
    \int_decr:N \l__tnscalc_numcol_int
    % Column~\int_use:N \l__tnscalc_numcol_int :~
    % \tl_map_inline:nn {#1}
    %   { (##1) }
    % \par
    % \int_decr:N \l__tnscalc_numcol_int
  }
\ExplSyntaxOff

\begin{document}
\splittab{\\}{&}{ a & b & c \\ 1 & 2 & 3 }
\end{document}

相关内容