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

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

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

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

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

6 ответов


пример руководство:

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

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

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

что довольно глупо, я знаю, но это примерно то, что я собираюсь пойти с LaTeX - это просто не так сенсационно, как только я начинаю смотреть на код TeX... Мне нравится метод xparse Мистера Робертсона, хотя, возможно, я попробую...


общая идея создания "необязательных аргументов" заключается в том, чтобы сначала определить промежуточную команду, которая сканирует вперед, чтобы определить, какие символы появляются дальше в потоке токенов, а затем вставляет соответствующие макросы для обработки аргументов. Это может быть довольно утомительно (хотя и не сложно), используя общее Программирование TeX. Латекс \@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) can затем используйте, чтобы проверить, действительно ли второй аргумент присутствовал или нет. См. документацию для других типов необязательных аргументов, которые разрешены.


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

\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

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


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

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