LaTeX Необязательные аргументы

132

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

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

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

\sec{Hello}
%Output: Hello
\sec{Hello}{Hi}
%Output: Hello and Hi
Verhogen
источник

Ответы:

176

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

\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.
Мик
источник
21
Я думаю, что вопрос заключался в том, как определить , был ли указан необязательный аргумент, а не указание по умолчанию.
Конрад Рудольф
43
Хотя это правда, я нашел этот вопрос, когда искал способ предоставить аргумент по умолчанию, поэтому этот ответ был для меня самым полезным.
Tanner Swett 08
26

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

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

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

\ Documentclass {статья}
\ Usepackage {xparse}
\ Начать {документ}
\ DeclareDocumentCommand \ sec {mg} {%
    {# 1%
        \ IfNoValueF {# 2} {и # 2}%
    }%
}
(\ Сек {} Привет)
(\ Сек {} {Привет Привет})
\ Конец {документ}

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

Уилл Робертсон
источник
4
Будет! Это не работает. Выход:(Hello and ) (Hello and Hi)
Алексей Малистов
Спасибо за отзыв, Алексей. Я подозреваю, что вы используете старую версию xparse; в последнее время над ним было проделано много работы. TeX Live 2009 только что вышел :)
Уилл Робертсон
24

Все вышесказанное показывает, как сложно сделать красивую, гибкую (или запретить перегруженную) функцию в 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 мистера Робертсона, возможно, я попробую ...

Demis
источник
Мне нравится этот подход. Более похож на программирование и поэтому его легче читать. Хорошая работа!
Loved.by.Jesus
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
Алексей Малистов
источник
Я думал, что TeX понимает под параметрами соответствующее количество первых «ящиков» после команды. эта «коробка» записана в фигурных скобках или представляет собой один символ. То есть. x^2+1или x^{2+1} У меня вопрос, проверяет ли ваша команда наличие фигурных скобок? Можно ли создать команду LaTeX, \secпроизводящую: «A, b, c и d» для команды \sec{A}[b,c,d], «A и b» для \sec{A}[b] and "A" for \ sec {A} `?
Crowley
У вас есть два вопроса. 1) Да, моя команда проверяет наличие фигурных скобок. 2) Да, можно создать макрос для \sec{A}[b,c,d]или \sec{A}[b]или \sec{A}.
Алексей Малистов
6

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

CSAR
источник
-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"
dreamlax
источник