LaTeX3 迭代和标记列表比较-代码改进

LaTeX3 迭代和标记列表比较-代码改进

我正在尝试创建一个使用两个参数的完全可扩展函数。第一个参数用于tokenlist测试第二个参数 another tokenlist

测试是逐个字符的比较(我知道正则表达式是更好的解决方案,事实上也许纯 TeX 也很好),但我正在尝试熟悉 LaTeX3。

你会如何改进代码?经过更多测试的代码可用于检查数字、元音、有效字符输入等。

\documentclass{article}
\usepackage{expl3,xcolor}
\begin{document}
\ExplSyntaxOn
\def\PASS{\par{\bfseries\textcolor{green!80!blue}{PASS\ }}}
\def\FAIL{\par{\bfseries\textcolor{red!70!black}{FAIL\ }}}
\cs_new:Npn \test_two:nn #1#2 {

% syntactic cyanide for expandafters
        \cs_generate_variant:Nn \tl_if_in:NnTF {ff }
        \cs_generate_variant:Nn \cs_gset:Npn {Npf}
        \cs_generate_variant:Nn \tl_set_eq:NN {Nn}      
        \cs_generate_variant:Nn \int_step_inline:nnnn {nnfn, nnVn}    
        \cs_generate_variant:Nn \int_set_eq:NN {No,Nf}
        \cs_generate_variant:Nn \tl_gset:Nn {No,Nf}

% set the lists     
        \tl_gset:Nx \temp {#2}
          \tl_gset:Nx \temp_needle_tl {#1}
        \tl_gset:Nn \head_tl {\tl_head:V \temp_needle_tl } 
          \tl_gset:Nn \start_tl {\temp_needle_tl }

% print some values         
        head~at~start~ \head_tl\par
        tail~at~ start~ \start_tl\ par

% set iteration limit 
            \int_set_eq:Nf  \g_tmpa_int {\tl_count:V\temp_needle_tl}
            Number~of~items~to~test \int_use:N \g_tmpa_int\par

% iteration             
        \int_step_inline:nnnn {1} {1} {\g_tmpa_int}{

% test value         
               \tl_if_in:ffTF {\temp} {\head_tl}
                {          
                       \PASS  \head_tl\ ~~\start_tl \par
                } 
               {
                       \FAIL   \head_tl\ ~~\start_tl \par
               }

%           Swap and go
             \tl_gset:Nn \head_tl {\tl_head:f\start_tl } 
             \tl_gset:Nf \oldtail_tl {\start_tl }
             \tl_gset:Nn \start_tl {\tl_tail:f \oldtail_tl}
       }
     }
\test_two:nn {1234567890AAA}{-1234567890)(}
\test_two:nn {apple}{aeiouAEIOU)(} 

\end{document}

编辑:最初我要求更正一些错误,我已经修复了。现在我要求改进代码。

答案1

正如评论中所述,如果您想要一个可扩展的功能,那么不能使用任何其中有不可扩展的函数。此外,问题中还有各种奇怪/错误的参数类型分配。但是,整个过程可以更紧凑地完成,至少如果我们可以假设我们不必担心空格、括号组或类似的东西。

\documentclass{article}
\usepackage{expl3,xcolor}
\begin{document}
\def\PASS{\par{\bfseries\textcolor{green!80!blue}{PASS\ }}}
\def\FAIL{\par{\bfseries\textcolor{red!70!black}{FAIL\ }}}
\ExplSyntaxOn
\cs_new:Npn \ylcompare #1#2
  {
     \__yl_compare_auxi:nN {#2} #1 \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \__yl_compare_auxi:nN #1#2
  {
    \quark_if_recursion_tail_stop:N #2
    \__yl_compare_auxii:nN {#1} #2
    \__yl_compare_auxi:nN {#1}
  }
\cs_new:Npn \__yl_compare_auxii:nN #1#2
  {
    \__yl_compare_auxiii:NN #2 #1 \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \__yl_compare_auxiii:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2 { \FAIL #1 }
    \str_if_eq:nnT {#1} {#2}
      {
        \use_i_delimit_by_q_recursion_stop:nw { \PASS #1 }
      }
    \__yl_compare_auxiii:NN #1
  }
\ExplSyntaxOff

\ylcompare{1234567890AAA}{-1234567890)(}
\ylcompare{apple}{aeiouAEIOU)(} 

\end{document}

这里的想法是针对要检查的列表设置一个可扩展的递归,然后针对“允许”列表启动第二个递归。这使用了 等提供\q_recursion_tail并在 中讨论的通用递归思想interface3

如果需要涵盖更复杂的情况,可以使用“令牌列表操作”方法的实现,例如用于可扩展案例的变化。


对于检查整数值(或实际上是实数)的情况,我会对各种子循环进行硬编码。(事实上,除非绝对需要,否则我可能会以非扩展的方式执行此操作。例如,siunitx测试有效输入但不通过扩展来执行此操作,因为它进行排版,而l3fp进行基于扩展的值检查,因为它需要可扩展。)假设我们坚持采用expl3可扩展的方法,可以这样做

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \ylinttest #1
  { \__yl_compare_auxi:N #1 \q_recursion_tail \q_recursion_stop }
\cs_new:Npn \__yl_compare_auxi:N #1
  {
    \quark_if_recursion_tail_stop_do:Nn #1 { FAIL }
    \bool_if:nTF
      {
           \str_if_eq_p:nn {#1} { + }
        || \str_if_eq_p:nn {#1} { - }
      }
      { \__yl_compare_auxi:N }
      { \__yl_compare_auxii:N #1 }
  }
\cs_new:Npn \__yl_compare_auxii:N #1
  {
    \quark_if_recursion_tail_stop_do:Nn #1 { PASS }
    \__yl_compare_auxiii:N #1
    \__yl_compare_auxii:N
  }
\cs_new:Npn \__yl_compare_auxiii:N #1
  {
    \__yl_compare_auxiv:NN #1 0123456789 \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \__yl_compare_auxiv:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      { \use_i_delimit_by_q_recursion_stop:nw { FAIL } }
    \str_if_eq:nnT {#1} {#2}
      { \use_none_delimit_by_q_recursion_stop:w }
    \__yl_compare_auxiv:NN #1
  }
\ExplSyntaxOff

\ylinttest{1234567890}
\ylinttest{---12345}
\ylinttest{---1-2345}
\ylinttest{12345A}
\ylinttest{}

\end{document}

这里的想法是,有效整数可以有一个或多个,+或者-在开头后跟至少一个数值。通过将循环拆分为几部分,无需尝试跟踪状态。在实际情况下,您可能会在测试后有两条代码路径,而不是PASS/ ,并且/可以选择合适的代码路径。FAIL\use_i:n\use_ii:nn

可以使用相同的方法测试浮点数,但需要更多循环。我可能会看一下 Brunol3fp为此编写的版本:它运行良好且经过全面测试,因此是一个很好的起点。

相关内容