LaTeX Необязательные аргументы - PullRequest
112 голосов
/ 28 ноября 2009

Как создать команду с необязательными аргументами в LaTeX? Что-то вроде:

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

Тогда я могу назвать это как

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

Ответы [ 6 ]

150 голосов
/ 28 ноября 2009

Пример из руководства :

\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.
23 голосов
/ 28 ноября 2009

Общая идея создания «необязательных аргументов» заключается в том, чтобы сначала определить промежуточную команду, которая сканирует вперед, чтобы определить, какие символы идут дальше в потоке токенов, а затем вставляет соответствующие макросы для обработки аргумента (ов), появляющихся как подходящее. Это может быть довольно утомительно (хотя и не сложно) при использовании общего программирования TeX. LaTeX's \@ifnextchar весьма полезен для таких вещей.

Лучший ответ на ваш вопрос - использовать новый пакет xparse. Он является частью пакета программирования LaTeX3 и содержит широкие возможности для определения команд с совершенно произвольными необязательными аргументами.

В вашем примере у вас есть макрос \sec, который принимает один или два квадратных аргумента. Это будет реализовано с использованием xparse со следующим:

\documentclass{article}
\usepackage{xparse}
\begin{document}
\DeclareDocumentCommand\sec{ m g }{%
    {#1%
        \IfNoValueF {#2} { and #2}%
    }%
}
(\sec{Hello})
(\sec{Hello}{Hi})
\end{document}

Аргумент { m g } определяет аргументы \sec; m означает «обязательный аргумент», а g - «необязательный аргумент в скобках». \IfNoValue(T)(F) затем можно использовать для проверки наличия второго аргумента или нет. См. Документацию для других типов необязательных аргументов, которые разрешены.

22 голосов
/ 06 сентября 2011

Все вышеперечисленное показывает, что в 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 ... Мне нравится метод xparse мистера Робертсона, хотя возможно я попробую ...

13 голосов
/ 28 ноября 2009

Все, что вам нужно, это следующее:

\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
4 голосов
/ 26 мая 2017

У меня была похожая проблема, когда я хотел создать команду \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 с необязательным аргументом

0 голосов
/ 02 декабря 2009

Вот моя попытка, она не совсем соответствует вашим спецификациям. Проверено не полностью, поэтому будьте осторожны.

\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"
...