在 newcommand 中传递 3 个可选参数

在 newcommand 中传递 3 个可选参数

在我写的一篇数学文章中,我想用 $S(x;q,a)$ 表示某个数字。您可能已经猜到了,这个数字取决于三个参数 $x、q、a$。我想给这个表达式一个快捷方式,因为也许我最终会改变主意,宁愿将该数字表示为 $S(x;a,q)$ 或类似的数字。这样我就不必在整个文本中寻找这个表达式的实例了。

因此我在序言中按照以下方式定义了一个新命令:

\newcommand{\Sc}[3]{S(#1; #2, #3)}

这有效,即如果我现在输入\Sc{x}{q}{a},则将显示所需的输出。
大多数情况下,当我使用此命令时,我给命令的三个参数将按此顺序为 x、q 和 a。只有有时在使用时才会出现其他参数\Sc。所以捷径似乎是有可能的。

理想情况下,我只想将 type\Sc作为 的快捷方式\Sc{x}{q}{a}。但使用\Sc{a}{b}{c}必须保持有效,以便我可以根据\Sc需要将其他参数传递给 。
为了实现这一点,我尝试了

\newcommand{\Sc}[3][x][q][a]{S(#1; #2, #3)}

但显然,据我所知,中最多允许一个可选参数\newcommand。(如果这是错的,请纠正我。)

有没有办法让我的新命令的所有三个参数都成为可选的,并且 x、q 和 a 都是默认值?

编辑:显然,我没有把重点表达得足够清楚。我想要排版的是两样东西。一个是带有三个参数 x、q 和 a 的 $S(x;q,a)$。另一个是 $S(_; _, _)$,我还不知道这三个参数是什么。使用同一个命令 ,两者都应该可以实现\Sc
为了显示 $S(x;q,a)$,我只想输入\Sc。因此,从某种意义上说,参数 x(作为第一个参数)、q(第二个)和 a(第三个)应该是默认的。为了显示带有不同于 (x,q,a) 的参数三元组 (_, _, _)$,我想使用带有所有三个参数的命令。例如,我会输入$\Sc{x}{q}{b}$以生成 $S(x;q,b)$。

答案1

我认为有两种方法可以实现这一点。

xparse您可以使用它\NewDocumentCommand来创建带有多个可选参数的新命令。一旦超过两个可选参数,使用就会变得有点笨拙,键值接口可能是更好的解决方案。笨拙之处在于,对于三个连续的可选参数,如果您只想指定第三个,则还必须指定第一个和第二个。如果您只想指定第二个,则还必须指定第一个。否则,无法知道您指定的是三个可选参数中的哪一个。

MWE 使用xparse

\documentclass{article}
\usepackage{xparse} % Automatically included in recent LaTeX releases;
                    % load manually as here for older releases.

\NewDocumentCommand{\Sc}{ O{x} O{q} O{a} }{%
  S(#1; #2, #3)
}%

\begin{document}
\Sc

\Sc[w][y][z] % change all three arguments

\Sc[m]       % change only the first argument

\Sc[x][m]    % change only the second argument

\Sc[x][q][m] % change only the third argument
\end{document}

另一种方法是使用xargs包,它提供了\newcommandx宏,反过来,宏也允许您指定具有默认值的可选参数,但语法和用法略有不同。如果您只想更改第三个参数,则不必明确提供前两个参数的默认值,但您仍必须为缺少的参数指定空的占位符分隔符。

MWE 使用xargs

\documentclass{article}
\usepackage{xargs}

\newcommandx*{\Sc}[3][1=x,2=q,3=a,usedefault]{%
  S(#1; #2, #3)
}%

\begin{document}
\Sc

\Sc[w][y][z] % change all three arguments

\Sc[m]       % change only the first argument

\Sc[][m]     % change only the second argument

\Sc[][][m]   % change only the third argument
\end{document}

可能还有其他更优雅的解决方案。对于三个连续的可选参数,您需要小心如果用户省略任何参数会发生什么。

答案2

我不喜欢在连续的可选参数之间指定而没有强制参数的想法:

如果您希望指定其中一个可选参数,那么您还需要至少指定位于此可选参数左侧的所有可选参数。

我建议使用一个可选参数来做事,其中嵌套三个强制参数:

(如果您改变主意,您只需改变\InnerSc其论点的方式。)

\documentclass{article}
\newcommand{\InnerSc}[3]{S(#1; #2, #3)}
\newcommand\Sc[1][{{x}{q}{a}}]{\InnerSc#1}

\begin{document}
\[ \Sc = \Sc[{a}{b}{c}] \]
\end{document}

在此处输入图片描述

如果你喜欢过度杀伤,你可以使用 xparse/expl3 创建一个\Sc带有可选参数的命令,通过 key=value-interface,你可以只指定那些与默认值不同的内容:

\documentclass{article}

\RequirePackage{xparse}
\ExplSyntaxOn
% key=value-interface by means of package l3keys:
%-------------------------------------------------------
% Macros holding default-values of keys
%   \cs_new:Nn in order to get an error-message at this place
%   in case one of the macros  \__MYMODULE_Paramater_X: , 
%   \__MYMODULE_Paramater_Q: , \__MYMODULE_Paramater_A:
%   is already defined.
%   While carrying out an instance of \Sc these macros are
%   used as scratch-macros holding the values of the keys
%   ParameterX, ParameterQ and ParameterA.
\cs_new:Nn \__MYMODULE_Paramater_X: {x}
\cs_new:Nn \__MYMODULE_Paramater_Q: {q}
\cs_new:Nn \__MYMODULE_Paramater_A: {a}
\keys_define:nn { MYMODULE } {
  ParameterX.cs_set:Np = \__MYMODULE_Paramater_X: {},
  ParameterX.default:n = x,
  ParameterQ.cs_set:Np = \__MYMODULE_Paramater_Q: {},
  ParameterQ.default:n = q,
  ParameterA.cs_set:Np = \__MYMODULE_Paramater_A: {},
  ParameterA.default:n = a,
}
\NewDocumentCommand\Sc{O{}}{
  \group_begin:
  \keys_set:nn{ MYMODULE }{#1}
   S(\__MYMODULE_Paramater_X:;~\__MYMODULE_Paramater_Q:,~\__MYMODULE_Paramater_A:)
  \group_end:
}
\ExplSyntaxOff

\begin{document}
\[ \Sc = \Sc[ParameterX=a, ParameterQ=b, ParameterA=c] \]

\[ \Sc = \Sc[ParameterX=a, ParameterA=c, ParameterQ=b] \]

\[ \Sc = \Sc[ParameterX=a, ParameterA=c] \]

\[ \Sc = \Sc[ParameterQ=w] \]

\[ \Sc = \Sc[ParameterQ, ParameterX, ParameterA] \]
\end{document}

在此处输入图片描述

在此代码示例中,键具有较长的名称,如ParameterXParameterQParameterA。因此,当坚持使用这些名称时,您必须输入很多内容。

我选择这些长名称是为了让您在查看代码示例时更容易理解所有内容。

当然,在现实生活中,我会给键起一些不太长的名字。

我可能会将它们命名为X/ Q/A或类似的名字。

或者我可以给它们赋予语义名称。在这个例子中我无法做到这一点,因为在您的问题中,您仅揭示了模式表达式S(#1; #2, #3)表示(无论如何)数字,但您没有揭示对于该模式的各个组成部分,是否#1存在#2针对#3此类表达式上下文的专门术语。
(例如,模式的表达式\frac{#1}{#2}表示分数。#1该模式的组成部分表示分子。该模式的组成部分#2表示分母。“分子”和“分母”是针对分数上下文的专门术语。因此,在用于排版分数的 key=value 接口中,键可以分别命名为“分子”和“分母”。)

答案3

该语法\Sc[y;r,b]看起来非常实用且语义化,但您以后可以按照自己喜欢的任何方式更改输出。

\documentclass{article}
\usepackage{amsmath}

\NewDocumentCommand{\Sc}{>{\SplitArgument{1}{;}}O{x;q,a}}{\ScAux#1}
\NewDocumentCommand{\ScAux}{m >{\SplitArgument{1}{,}}m}{S(#1;\ScAuxA#2)}
\NewDocumentCommand{\ScAuxA}{mm}{#1,#2}

\begin{document}

$\Sc$

$\Sc[y;r,b]$

\end{document}

诀窍在于,带\SplitArgument{1}{;}参数的函数会被分成两对括号组。因此,不带可选参数的调用将依次执行

\ScAux{x}{q,a}
S(x;\ScAuxA{q}{a})
S(x;q,a)

根据需要。1指的是预期分隔符的数量,第一个分隔符为分号,第二个分隔符为逗号。

如果我们调用\Sc[y;r,b]来获取

\ScAux{y}{r,b}
S(x;\ScAuxA{r}{b})
S(x;r,b)

在此处输入图片描述

答案4

与@UlrichDiez 提供的 keyval 解决方案类似,但使用包semantex(免责声明:我是作者)。

\documentclass{article}

\usepackage{semantex}

\NewSymbolClass{\MySymbolClass}

\NewObject{\MySymbolClass}{\Sc}{S}[
    data provide=data x,
    data provide=data q,
    data provide=data a,
    define keys[1]={
        {x}{ data set={data x}{#1} },
        {q}{ data set={data q}{#1} },
        {a}{ data set={data a}{#1} },
    },
    x={x},
    q={q},
    a={a},
    parse options={
        set arg keys x={
            sep={\SemantexDataGetExpNot{data x}},
            other sep={;}{\SemantexDataGetExpNot{data q}},
            sep={\SemantexDataGetExpNot{data a}},
        },
    },
]

\begin{document}

\( \Sc = \Sc[x=x,q=q,a=a] \neq \Sc[x=7,q=14,a=23] \)

\end{document}

在此处输入图片描述

相关内容