定义一个命令,扫描每个参数的宏“寻找”一个标记

定义一个命令,扫描每个参数的宏“寻找”一个标记

知道每个具有条件可选参数的命令声明,\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工作的)。

相关内容