views:

440

answers:

4

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
A: 

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.
The MYYN
I think the question was about how to determine *whether* an optional argument was given, not providing a default.
Konrad Rudolph
+3  A: 

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.

Will Robertson
Will! It does not work. Output: `(Hello and ) (Hello and Hi)`
Alexey Malistov
Thanks for the feedback, Alexey. I suspect you're using an older version of xparse; there's been a lot of work done on it recently. TeX Live 2009 has just been released :)
Will Robertson
+2  A: 

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
Alexey Malistov
I thought TeX understands as parameters appropriate count of first 'boxes' after command. this 'box' is written in curly braces or it's one symbol. Ie. `x^2+1` or `x^{2+1}` So I have question, does your command test presence of braces?Is it possible to create LaTeX command `\sec` producing:"A, b,c and d" for command `\sec{A}[b,c,d]`,"A and b" for `\sec{A}[b] and"A" for `\sec{A}`?
Crowley
You have two questions. 1) Yes, my command test presence of braces. 2) Yes, it is possible to create macro for `\sec{A}[b,c,d]` or `\sec{A}[b]` or `\sec{A}`.
Alexey Malistov
A: 

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"
dreamlax