如果\DeclareDocumentCommand
我有两个连续的可选参数,我该如何表示第一个参数缺失了?
例如:
\documentclass{article}
\usepackage{xparse}
\begin{document}
\ExplSyntaxOn
\DeclareDocumentCommand{\test}{o o}
{
\IfValueTF{#1}
{#1}{#2}
}
\ExplSyntaxOff
\test[][1]
\end{document}
不产生任何结果,我希望它产生 1。
答案1
不传递任何内容和不使用它之间是有区别的。事实上,你的测试\IfValueTF{#1}
结果为真,因为它#1
有一个值,即使这个值可能是空的。
要测试是否传递空参数(换句话说,不传递任何内容),请使用以下技术如何检查宏值是否为空或不会使用纯 TeX 条件创建文本?:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\DeclareDocumentCommand{\test}{o o}
{
\if\relax\detokenize{#1}\relax
#2%
\else
#1%
\fi
}
\ExplSyntaxOff
\begin{document}
\test[][1]
\end{document}
或者使用真正的 LaTeX3 检查:
\ExplSyntaxOn
\DeclareDocumentCommand{\test}{o o}
{
\tl_if_blank:nTF { #1 }
{ #2 }
{ #1 }
}
\ExplSyntaxOff
请注意,如果用户界面中有 2 个可选参数使用相同的分隔符,则会引起混淆。仅有的传递第二个参数的另一种方法是同时指定第一个参数,这样它就不是可选的了。为此xparse
提供调整参数分隔符的方法:
\ExplSyntaxOn
\DeclareDocumentCommand{\test}{o d()}
{
\IfValueTF{#1}
{#1}{#2}
}
\ExplSyntaxOff
上面的 定义\test[<first>](<second>)
有两个可选参数。第一个使用 ,[]
而第二个使用()
,明确区分了它们的用法,并且它们是完全可选的,如\test(1)
。
对于更复杂(多个)的参数,通常建议创建键值接口。
答案2
LaTeX 内核中有一些命令允许连续使用两个或三个可选参数:
\makebox[<length>][<alignment>]{<text>}
\parbox[<outer alignment>][<height>][<inner alignment>]{<width>}{<text>}
(请注意minipage
接受与 相同的参数\parbox
,当然没有最后一个)。在这两种情况下,第一个之后的可选参数只有在前一个参数出现时才有意义。例如,选项<alignment>
只有\makebox
在<width>
指定 a 时才有意义。 的情况\parbox
略有不同,但如果未指定,第一个可选参数也用于第三个;可能更好的语法应该是
\parbox[<outer alignment>]{<width>}[<height>][<inner alignment>]{<text>}
以便永远不会要求一个可选参数。
(及其变体) 命令接受两个可选参数\cite
:biblatex
\cite[<postnote>]{<key>}
\cite[<prenote>][<postnote>]{<key>}
这里有一个空的<postnote>
必须<prenote>
如果只需要a,则指定
\cite[See][]{mykey}
在amsref
提出了一种替代语法:而不是\cite[<postnote>]{<key>}
,对于典型的情况,人们希望
[3,引理 4]
传统上输入为\cite[Lemma~4]{mykey}
,该包提供
\cite{mykey}*{Lemma~4}
我觉得这很有趣,但它不符合标准做法。请注意,这将允许(但实际上并不允许)以下语法:
\cite[<prenote>]{key}*{<postnote>}
这可能会更具可读性。
您会发现,构建良好的用户界面并非易事。但每当出现可选参数几乎成为必需参数的情况时,就必须深思熟虑。
在这些情况下,一个好的替代方案是键值接口;\parbox
例如
\PARBOX[
outer=<character>,% c (default), t or b
inner=<character>,% default=outer, c, t, b or s
height=<length>,
]{<width>}{<text>}
并且可以很容易地使outer
和选项接受更长的值,inner
例如top
、bottom
或。center
spread
当选项彼此独立时,应该优先使用键值接口。
xparse
也就是说,你可以通过定义新的“检查命令”来增强功能
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\IfBlankTF}{mmm}
{
\tl_if_blank:nTF { #1 } { #2 } { #3 }
}
\ExplSyntaxOff
以便您以后可以将命令定义为
\NewDocumentCommand{\test}{o o}
{%
\IfNoValueTF{#1}
{%
Something for the case of no optional argument%
}%
{%
\IfNoValueTF{#2}
{%
Something with #1 for the case of just one optional argument%
}%
{%
\IfBlankTF{#1}
{%
Something with #2 for the case \string\test[][...]%
}%
{%
Something with #1 and #2%
}%
}%
}%
}