给定一个标记列表,例如\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