LaTeX Optional Arguments
LatexOptional ArgumentsLatex Problem Overview
How do you create a command with optional arguments in LaTeX? Something like:
\newcommand{\sec}[2][]{
\section*{#1
\ifsecondargument
and #2
\fi}
}
}
Then, I can call it like
\sec{Hello}
%Output: Hello
\sec{Hello}{Hi}
%Output: Hello and Hi
Latex Solutions
Solution 1 - Latex
Example from the guide:
\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.
Solution 2 - Latex
All of the above show hard it can be to make a nice, flexible (or forbid an overloaded) function in LaTeX!!! (that TeX code looks like greek to me)
well, just to add my recent (albeit not as flexible) development, here's what I've recently used in my thesis doc, with
\usepackage{ifthen} % provides conditonals...
Start the command, with the "optional" command set blank by default:
\newcommand {\figHoriz} [4] [] {
I then have the macro set a temporary variable, \temp{}, differently depending on whether or not the optional argument is blank. This could be extended to any passed argument.
\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)
Then I run the macro using the \temp{} variable for the two cases. (Here it just sets the short-caption to equal the long caption if it wasn't specified by the user).
\begin{figure}[!]
\begin{center}
\includegraphics[width=350 pt]{#3}
\temp %see above for caption etc.
\label{#2}
\end{center}
\end{figure}
}
In this case I only check for the single, "optional" argument that \newcommand{} provides. If you were to set it up for, say, 3 "optional" args, you'd still have to send the 3 blank args... eg.
\MyCommand {first arg} {} {} {}
which is pretty silly, I know, but that's about as far as I'm going to go with LaTeX - it's just not that sensical once I start looking at TeX code... I do like Mr. Robertson's xparse method though, perhaps I'll try it...
Solution 3 - Latex
The general idea behind creating "optional arguments" is to first define an intermediate command that scans ahead to detect what characters are coming up next in the token stream and then inserts the relevant macros to process the argument(s) coming up as appropriate. This can be quite tedious (although not difficult) using generic TeX programming. LaTeX's \@ifnextchar
is quite useful for such things.
The best answer for your question is to use the new xparse
package. It is part of the LaTeX3 programming suite and contains extensive features for defining commands with quite arbitrary optional arguments.
In your example you have a \sec
macro that either takes one or two braced arguments. This would be implemented using xparse
with the following:
\documentclass{article} \usepackage{xparse} \begin{document} \DeclareDocumentCommand\sec{ m g }{% {#1% \IfNoValueF {#2} { and #2}% }% } (\sec{Hello}) (\sec{Hello}{Hi}) \end{document}The argument
{ m g }
defines the arguments of \sec
; m
means "mandatory argument" and g
is "optional braced argument". \IfNoValue(T)(F)
can then be used to check whether the second argument was indeed present or not. See the documentation for the other types of optional arguments that are allowed.
Solution 4 - Latex
All you need is the following:
\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
Solution 5 - Latex
I had a similar problem, when I wanted to create a command, \dx
, to abbreviate \;\mathrm{d}x
(i.e. put an extra space before the differential of the integral and have the "d" upright as well). But then I also wanted to make it flexible enough to include the variable of integration as an optional argument. I put the following code in the preamble.
\usepackage{ifthen}
\newcommand{\dx}[1][]{%
\ifthenelse{ \equal{#1}{} }
{\ensuremath{\;\mathrm{d}x}}
{\ensuremath{\;\mathrm{d}#1}}
}
Then
\begin{document}
$$\int x\dx$$
$$\int t\dx[t]$$
\end{document}
Solution 6 - Latex
Here's my attempt, it doesn't follow your specs exactly though. Not fully tested, so be cautious.
\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"
\sec{a}{b}
% outputs "a and b"