162

如何在 LaTeX 中创建带有可选参数的命令?就像是:

\newcommand{\sec}[2][]{
    \section*{#1
        \ifsecondargument
            and #2
        \fi}
    }
}

然后,我可以这样称呼它

\sec{Hello}
%Output: Hello
\sec{Hello}{Hi}
%Output: Hello and Hi
4

6 回答 6

223

指南中的示例:

\newcommand{\example}[2][YYY]{Mandatory arg: #2;
                                 Optional arg: #1.}

This defines \example to be a command with two arguments, 
referred to as #1 and #2 in the {<definition>}--nothing new so far. 
But by adding a second optional argument to this \newcommand 
(the [YYY]) the first argument (#1) of the newly defined 
command \example is made optional with its default value being YYY.

Thus the usage of \example is either:

   \example{BBB}
which prints:
Mandatory arg: BBB; Optional arg: YYY.
or:
   \example[XXX]{AAA}
which prints:
Mandatory arg: AAA; Optional arg: XXX.
于 2009-11-28T10:50:19.093 回答
30

创建“可选参数”背后的一般思想是首先定义一个中间命令,该命令向前扫描以检测令牌流中接下来出现的字符,然后插入相关的宏以适当地处理出现的参数。使用通用 TeX 编程可能会非常乏味(尽管并不困难)。LaTeX\@ifnextchar对这些事情非常有用。

您问题的最佳答案是使用新xparse包。它是 LaTeX3 编程套件的一部分,包含用于定义具有任意可选参数的命令的广泛功能。

在您的示例中,您有一个\sec宏,它接受一个或两个大括号参数。这将通过xparse以下方式实现:

\documentclass{文章}
\使用包{xparse}
\开始{文档}
\DeclareDocumentCommand\sec{ 毫克 }{%
    {#1%
        \IfNoValueF {#2} { 和 #2}%
    }%
}
(\sec{你好})
(\sec{你好}{你好})
\结束{文档}

参数{ m g }定义了\sec; m意思是“强制参数”并且g是“可选的大括号参数”。\IfNoValue(T)(F)然后可以用来检查第二个参数是否确实存在。有关允许的其他类型的可选参数,请参阅文档。

于 2009-11-28T11:32:00.073 回答
29

以上所有内容都表明很难在 LaTeX 中创建一个好的、灵活的(或禁止重载的)函数!!!(对我来说,TeX 代码看起来像希腊语)

好吧,只是为了添加我最近(尽管不是那么灵活)的开发,这是我最近在我的论文文档中使用的,与

\usepackage{ifthen}  % provides conditonals...

启动命令,默认情况下将“可选”命令设置为空白:

\newcommand {\figHoriz} [4] []  {

然后我让宏设置一个临时变量 \temp{},这取决于可选参数是否为空白。这可以扩展到任何传递的参数。

\ifthenelse { \equal {#1} {} }  %if short caption not specified, use long caption (no slant)
    { \def\temp {\caption[#4]{\textsl{#4}}} }   % if #1 == blank
    { \def\temp {\caption[#1]{\textsl{#4}}} }   % else (not blank)

然后我使用 \temp{} 变量为这两种情况运行宏。(如果用户没有指定,这里它只是将短标题设置为等于长标题)。

\begin{figure}[!]
    \begin{center}
        \includegraphics[width=350 pt]{#3}
        \temp   %see above for caption etc.
        \label{#2}
    \end{center}
\end{figure}
}

在这种情况下,我只检查 \newcommand{} 提供的单个“可选”参数。如果你要为 3 个“可选”参数设置它,你仍然需要发送 3 个空白参数......例如。

\MyCommand {first arg} {} {} {}

这很愚蠢,我知道,但这就是我将要使用 LaTeX 的程度 - 一旦我开始查看 TeX 代码,它就不是那么有意义了......不过,我确实喜欢 Robertson 先生的 xparse 方法,也许我会试试...

于 2011-09-06T04:30:39.350 回答
11

您只需要以下内容:

\makeatletter
\def\sec#1{\def\tempa{#1}\futurelet\next\sec@i}% Save first argument
\def\sec@i{\ifx\next\bgroup\expandafter\sec@ii\else\expandafter\sec@end\fi}%Check brace
\def\sec@ii#1{\section*{\tempa\ and #1}}%Two args
\def\sec@end{\section*{\tempa}}%Single args
\makeatother

\sec{Hello}
%Output: Hello
\sec{Hello}{Hi}
%Output: Hello and Hi
于 2009-11-28T12:57:36.533 回答
11

当我想创建一个命令时,我遇到了类似的问题,\dx, 来缩写\;\mathrm{d}x(即在积分的微分之前放置一个额外的空格,并使“d”也直立)。但后来我也想让它足够灵活,以将积分变量作为可选参数包含在内。我将以下代码放在序言中。

\usepackage{ifthen}

\newcommand{\dx}[1][]{%
   \ifthenelse{ \equal{#1}{} }
      {\ensuremath{\;\mathrm{d}x}}
      {\ensuremath{\;\mathrm{d}#1}}
}

然后

\begin{document}
   $$\int x\dx$$
   $$\int t\dx[t]$$
\end{document}

给出带有可选参数的 \dx

于 2017-05-25T22:54:07.600 回答
-1

这是我的尝试,但它并不完全符合您的规格。没有完全测试,所以要小心。

\newcount\seccount

\def\sec{%
    \seccount0%
    \let\go\secnext\go
}

\def\secnext#1{%
    \def\last{#1}%
    \futurelet\next\secparse
}

\def\secparse{%
    \ifx\next\bgroup
        \let\go\secparseii
    \else
        \let\go\seclast
    \fi
    \go
}

\def\secparseii#1{%
    \ifnum\seccount>0, \fi
    \advance\seccount1\relax
    \last
    \def\last{#1}%
    \futurelet\next\secparse
}

\def\seclast{\ifnum\seccount>0{} and \fi\last}%

\sec{a}{b}{c}{d}{e}
% outputs "a, b, c, d and e"

\sec{a}
% outputs "a"

\sec{a}{b}
% outputs "a and b"
于 2009-12-02T03:50:05.267 回答