知道每个具有条件可选参数的命令声明,\foo{...}
扩展为可以通过以下更安全的版本\foo[default]{...}
来定义:\newcommand\foo[1][default]{...}
\newcommand\foo{\@ifnextchar[{\@foo}{\@foo[default]}}
\def\@foo[#1]#2{do something with #1 and #2}
然而,如果可选参数在强制参数之后声明,这种“测试”就会失败。因此(知道参数声明的顺序\@foo
不能改变):
\newcommand\foo{\@ifnextchar[{\@foo}{\@foo{}[default]}}
\def\@foo#1[#2]{do something with #1 and #2}
将会产生错误。
更一般地,如果\@bar
定义为必须包含两个(或更多,但一般情况除外)参数,但只有选修的 #2
不会出现在控制序列名称之后:
\def\@bar#1[#2]{#1 and #2}
那么,如何定义\bar
这样的条件:
\bar{a}[b] % returns "a and b"
\bar{a} % returns "a and default"
会得到满足吗?在这种情况下, 的定义中的内部命令\bar
会扫描 的所有参数标记,\bar
直到找到[
;如果没有找到,那么它只会声明\@bar#1[default]
。
这种行为应该类似于\@ifnextchar
(比如说),不同之处在于,仅作为参数标记存在\@iftoksexist
就足够了:char
\documentclass{article}
\makeatletter
\def\@iftoksexist#1#2#3{...} %
\def\mybar{%
\@iftoksexist{[} % or \@iftoksexist[{...}{...}
{
%use "\@mybar#1[#2]"
}
{
%use "\@mybar#1[default]"
}%
}
\def\@mybar#1[#2]{#1 and #2\par}
\makeatother
%
\begin{document}
%
\mybar{lorem}[ipsum]
\mybar{dolor}
\mybar{sit}[amet]
%
\end{document}
在这种情况下,将在每一个内部\@iftoksexist
进行搜索,产生以下输出:[
\mybar...
答案1
只要吸收强制性论点并“记住”它:
\makeatletter
\newcommand{\foo}[1]{%
\@ifnextchar[{\foo@aux{#1}}{\foo@aux{#1}[default]}%
}
\def\foo@aux#1[#2]{%
mandatory is `#1', optional is `#2'%
}
\makeatother
当然,这不是很强大,\DeclareRobustCommand
应该使用。
可选参数具有默认值的语法\foo{a}[b]{c}
可以以类似的方式定义:
\makeatletter
\newcommand{\foo}[1]{%
\@ifnextchar[{\foo@aux{#1}}{\foo@aux{#1}[default]}%
}
\def\foo@aux#1[#2]#3{%
first mandatory is `#1', optional is `#2', second mandatory is `#3'%
}
\makeatother
或者:
\usepackage{xparse}
\NewDocumentCommand{\foo}{mO{default}}{%
mandatory is `#1', optional is `#2'%
}
这当然是健壮的。但作为一般建议,避免使用尾随可选参数。\foo{a}[b]{c}
语法只是
\NewDocumentCommand{\foo}{mO{default}m}{%
first mandatory is `#1', optional is `#2', second mandatory is `#3'%
}
请注意,在第一种情况下,\foo{a}
如果没有可选参数,则空格将被忽略(原因是如何\@ifnextchar
工作的)。