如何将命令参数转换为可选参数?

如何将命令参数转换为可选参数?

LaTeX 允许使用可选参数。有时人们想改写通过使某些参数成为可选参数来执行命令:

\newcommand{\foo}[2]{
    #some commands
}

到:

\newcommand{\foo}[2][a]{
    #some commands
}

据我所知,LaTeX 不支持重载,因此无法以低耦合度实现某些参数的可选化,因为对方法的调用\foo{a}{b}必须转换为\foo[a]{b}。无法定义辅助方法\foo{}{}以使包向后兼容。

我想知道有哪些工具可以自动重写命令调用,或者宏来优雅地解决这个问题。

答案1

我不确定我是否理解了你的问题。恕我直言,你想写

\foo {a}{b} ... % The macro \foo with two parameters will be invoked
\foo {a}    ... % Another variant of the macro \foo with one parameter.
                % May be the missing parameter is substituted by default here

不幸的是,我的解决方案不可扩展。扫描括号的处理是在主处理器级别完成的。但你可以定义 \foo 的变体,从零到九个参数:

% NormalTeXsyntaxOn

\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\sdef#1{\expandafter\def\csname#1\endcsname}

\newcount\tmpnum
\def\foo{\def\fooC{}\tmpnum=0\futurelet\next\fooA}
\def\fooA{\ifx\next\bgroup \expandafter\fooB\else
   \csname foo\the\tmpnum\expandafter\expandafter\expandafter\endcsname\expandafter\fooC\fi}
\def\fooB#1{\addto\fooC{{#1}}\advance\tmpnum by1\futurelet\next\fooA}

\sdef{foo0}{foo without parameters}
\sdef{foo1}#1{foo with one parameter "#1"}
\sdef{foo2}#1#2{foo with two parameters "#1" and "#2"}
\sdef{foo3}#1#2#3{foo with three parameters "#1", "#2" and "#3"}
\sdef{foo4}#1#2#3#4{foo with four parameters "#1", "#2", "#3" and "#4"}

\foo ...
\foo {a} ...         
\foo {a}{b} ...         
\foo {a}{b}{c} ...      
\foo {a}{b}{c}{d} ...   
\foo {a}{b}{c}{d}{f} ...

% NormalTeXsyntaxOff

编辑作为示例,上面的代码被打包\multidef并显示了具有三个具有默认值的参数的宏的用法:

\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\ssdef#1{\expandafter\def\csname\string#1\endcsname}
\newcount\tmpnum
\def\multidef#1{%
  \def#1{\def\tmpparam{}\tmpnum=0
         \expandafter\futurelet\expandafter\next\csname\string#1-A\endcsname}%
  \ssdef{#1-A}{\ifx\next\bgroup \csname\string#1-B\expandafter\endcsname\else
      \csname \string#1\the\tmpnum\expandafter\expandafter\expandafter\endcsname
      \expandafter\tmpparam\fi}%
  \ssdef{#1-B}##1{\addto\tmpparam{{##1}}\advance\tmpnum by1
      \expandafter\futurelet\expandafter\next\csname\string#1-A\endcsname}%
}
\multidef\foo  % the \foo macro with various numbers of parameters is defined here
\ssdef{\foo0}{\fooNormal{defaultA}{defaultB}{defaultC}}
\ssdef{\foo1}#1{\fooNormal{defaultA}{defaultB}{#1}}
\ssdef{\foo2}#1#2{\fooNormal{defaulA}{#1}{#2}}
\ssdef{\foo3}{\fooNormal}
\def\fooNormal#1#2#3{foo invoked: param1=#1, param2=#2, param3=#3}

Test:
\foo ...            % does: \fooNormal{defaultA}{defaultB}{defaultC}
\foo {a} ...        % does: \fooNormal{defaultA}{defaultB}{a}
\foo {a}{b} ...     % does: \fooNormal{defaultA}{a}{b}
\foo {a}{b}{c} ...  % does: \fooNormal{a}{b}{c}

这是你想要的嗎?

相关内容