如何计算 xparse 参数说明符中的参数数量?

如何计算 xparse 参数说明符中的参数数量?

给定一个标记列表,例如\ArgumentSpecification包含一些参数规范,例如oom...

我怎样才能计算出结果参数的数量?

例如在这种情况下输出将是 3,可以很容易地用例如来计算\tl_count;然而在其他更复杂的情况下(+O-type 参数等)\tl_count是不正确的。


示例用例——如果我想编写一些NewDocumentCommand包装器来以某种方式“预处理”抓取的参数,但它需要知道有多少个可用的参数:

%! TEX program = lualatex
\documentclass{article}
\begin{document}

\ExplSyntaxOn
\NewDocumentCommand \__test {om} {
  #1 #2
}

\NewDocumentCommand \WrapperNewDocumentCommand {m} {
  \NewDocumentCommand \__inner {#1} {
    \tl_set:Nn \__argi {##1}
    %\tl_set:Nn \__argii {##2}  % only run this if `#1` contains two arguments
    %\tl_set:Nn \__argiii {##3}  % only run this if `#1` contains two arguments
  }
}

\WrapperNewDocumentCommand {m}

\__inner {abc}

\ExplSyntaxOff


\end{document}

在上面的例子中,如果恰好有 1 个参数,它就可以工作;但是我希望内部函数有条件地设置等等\__argi\__argii取决于有多少个参数。

备注:functional软件包源代码做了类似的事情https://github.com/lvjr/ functional/blob/main/ functional.sty#L154;然而它是硬编码\tl_count

答案1

当您\ShowCommand在用 定义的命令中执行时\NewDocumentCommand,LaTeX 会计算命令签名中的参数数量并进行拆分以进行漂亮的打印。例如:

\NewDocumentCommand \foo { e{^_} E{^_}{{a}{b}} >{\SplitArgument}+O{} m }
  { do stuff }
\ShowCommand \foo

印刷:

> \foo=document command:
  #1:e^
  #2:e_
  #3:E^{a}
  #4:E_{b}
  #5:>{\SplitArgument }+O{}
  #6:m
-> do stuff .

但是,这是由内部完成的\__cmd_split_signature:n,它会计算参数的数量并将它们存储在用于漂亮打印的标记列表中,并且没有公共接口。但您可以复制实现并执行类似操作。

这是一个可扩展的版本,它只计算参数并返回计数(内核命令的无耻抄袭,由于只需要计算参数,所以有些部分被切断了:)

\ExplSyntaxOn
\cs_new:Npn \usersixdigits_count_signature:n #1
  {
    \int_eval:n
      { 0 \__usersixdigits_split_signature_loop:Nw #1 \q_recursion_tail \q_recursion_stop }
  }
\cs_new:Npn \__usersixdigits_split_signature_loop:Nw #1
  {
    \quark_if_recursion_tail_stop:N #1
    \tl_if_exist:cTF { c__usersixdigits_show_type_#1_tl }
      {
        \use:c
          {
            __usersixdigits_show_
            \if_case:w \tl_use:c { c__usersixdigits_show_type_#1_tl } \exp_stop_f:
              delim \or: delims \or: delims_opt \or: opt \or:
              e \or: E \or: prefix \or: processor \fi: :Nw
          } #1
      }
      { +1 \__usersixdigits_split_signature_loop:Nw }
  }
\cs_set:Npn \__usersixdigits_tmp:w #1 #2
  {
    \quark_if_nil:nF {#1}
      { \tl_const:cn { c__usersixdigits_show_type_#1_tl } {#2} \__usersixdigits_tmp:w }
  }
\__usersixdigits_tmp:w t0 r1 d1 R2 D2 O3 e4 E5 +6 !6 >7 \q_nil \q_nil
\cs_new:Npn \__usersixdigits_show_delim:Nw #1 #2
  { +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_delims:Nw #1 #2 #3
  { +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_delims_opt:Nw #1 #2 #3 #4
  { +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_opt:Nw #1 #2
  { +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_e:Nw #1 #2
  { + \tl_count:n {#2} \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_E:Nw #1 #2 #3
  { + \tl_count:n {#2} \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_prefix:Nw #1
  { \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_processor:Nw #1 #2
  { \__usersixdigits_split_signature_loop:Nw }


\typeout { \usersixdigits_count_signature:n { m } }
\typeout { \usersixdigits_count_signature:n { +m } }
\typeout { \usersixdigits_count_signature:n { +!m } }
\typeout { \usersixdigits_count_signature:n { +!O{x} } }
\typeout { \usersixdigits_count_signature:n { >{\SplitArgument}+!O{x} } }

\typeout
  {
    \usersixdigits_count_signature:n
      { e{^_} E{^_}{{a}{b}} >{\SplitArgument}+O{} m }
  }


\stop

相关内容