如果\myB
接受两个可选参数,\myB
则将它们都设置为默认值,\myB[5]
将第一个设置为 ,5
将第二个设置为 ,\myB[5][10]
将第一个设置为 ,5
将第二个设置为10
。但是我们如何只设置#2
参数呢?这样做\myB[][10]
不会将第一个参数设置为默认值(只会使其消失)。
\documentclass{standalone}
\usepackage{xparse}
% each of two optional arguments defaults to zero
\NewDocumentCommand{\myB}{O{0}O{0}}
{%
myB: #1, #2%
}
\begin{document}
% how to call `myB` so that it only has #2 set? (not #1)
\myB[][6] % this is no good since `[]` removes default zero
\end{document}
答案1
作为Phelype Oleinik 建议您可以使用空的第一个可选参数,如果为空则分配默认值。我会使用参数处理器来做到这一点:
\ExplSyntaxOn
\cs_new_protected:Npn \__bdmmxvii_Oarg_proc:nn #1 #2
{
\tl_if_empty:nTF { #2 }
{ \cs_set:Npn \ProcessedArgument { #1 } }
{ \cs_set:Npn \ProcessedArgument { #2 } }
}
\NewDocumentCommand \twooptsA { >{ \__bdmmxvii_Oarg_proc:nn { 0 } }O{} O{0} }
{
myB:~#1,~#2
}
\ExplSyntaxOff
另外,我对星星的建议是:
\ExplSyntaxOn
\NewDocumentCommand \twooptsB { O{0} s O{0} }
{
myB:~#1,~#3
}
\ExplSyntaxOff
第三种选择是 key=value 语法:
\ExplSyntaxOn
\keys_define:nn { bdmmxvii }
{
,1 .tl_set:N = \__bdmmxvii_arg_a_tl
,1 .initial:n = 0
,2 .tl_set:N = \__bdmmxvii_arg_b_tl
,2 .initial:n = 0
}
\NewDocumentCommand \twooptsC { O{} }
{
\group_begin:
\keys_set:nn { bdmmxvii } { #1 }
\__bdmmxvii_twooptsC:VV \__bdmmxvii_arg_a_tl \__bdmmxvii_arg_b_tl
\group_end:
}
\cs_new:Npn \__bdmmxvii_twooptsC:nn #1 #2
{
myB:~#1,~#2
}
\cs_generate_variant:Nn \__bdmmxvii_twooptsC:nn { VV }
\ExplSyntaxOff
所有内容都包含在一个文档中:
\documentclass[]{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \__bdmmxvii_Oarg_proc:nn #1 #2
{
\tl_if_empty:nTF { #2 }
{ \cs_set:Npn \ProcessedArgument { #1 } }
{ \cs_set:Npn \ProcessedArgument { #2 } }
}
\NewDocumentCommand \twooptsA { >{ \__bdmmxvii_Oarg_proc:nn { 0 } }O{} O{0} }
{
myB:~#1,~#2
}
\NewDocumentCommand \twooptsB { O{0} s O{0} }
{
myB:~#1,~#3
}
\keys_define:nn { bdmmxvii }
{
,1 .tl_set:N = \__bdmmxvii_arg_a_tl
,1 .initial:n = 0
,2 .tl_set:N = \__bdmmxvii_arg_b_tl
,2 .initial:n = 0
}
\NewDocumentCommand \twooptsC { O{} }
{
\group_begin:
\keys_set:nn { bdmmxvii } { #1 }
\__bdmmxvii_twooptsC:VV \__bdmmxvii_arg_a_tl \__bdmmxvii_arg_b_tl
\group_end:
}
\cs_new:Npn \__bdmmxvii_twooptsC:nn #1 #2
{
myB:~#1,~#2
}
\cs_generate_variant:Nn \__bdmmxvii_twooptsC:nn { VV }
\ExplSyntaxOff
\begin{document}
\twooptsA\ \twooptsA[1][2] \twooptsA[1] \twooptsA[][2]
\twooptsB\ \twooptsB[1][2] \twooptsB[1] \twooptsB*[2]
\twooptsC\ \twooptsC[1=1,2=2] \twooptsC[1=1] \twooptsC[2=2]
\end{document}
一切结果都一样:
答案2
这是错误的语法,您应该考虑避免它。
无论如何,你可以对参数进行预处理。当然,你不能将第一个可选参数设置为空。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\IfEmpty}{mm}
{
\tl_if_blank:nTF { #2 }
{ \tl_set:Nn \ProcessedArgument { #1 } }
{ \tl_set:Nn \ProcessedArgument { #2 } }
}
\ExplSyntaxOff
\NewDocumentCommand{\myB}{>{\IfEmpty{0}}O{0}O{0}}{%
\#1 is #1 -- \#2 is #2
}
\begin{document}
\myB
\myB[1]
\myB[1][2]
\myB[][3]
\end{document}
答案3
另一种选择:使用不同的参数分隔符,使用说明符D
:
\NewDocumentCommand{\myB}{ D(){0} O{0} }{%
\#1 = #1, \#2 = #2%
}
\myB % #1 = 0, #2 = 0
\myB(1) % #1 = 1, #2 = 0
\myB[2] % #1 = 0, #2 = 2
\myB(1)[2] % #1 = 1, #2 = 2