2009-11-28 3 views
88

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

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

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

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

Соответствующий вопрос: [Различные определения команды с и без дополнительного аргумента] (http://tex.stackexchange.com/q/308/1347) , –

ответ

111

Пример из 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. 
+15

Я думаю, вопрос заключался в том, как определить *, был ли предоставлен необязательный аргумент, а не по умолчанию. –

+28

Хотя это правда, я нашел этот вопрос, ища способ предоставить аргумент по умолчанию, поэтому этот ответ был самым полезным для меня. –

18

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

+4

Будет! Это не работает. Вывод: '(Hello and) (Hello and Hi)' –

+0

Спасибо за отзыв, Алексей. Я подозреваю, что вы используете старую версию xparse; в последнее время проделана большая работа. TeX Live 2009 только что был выпущен :) –

12

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

\makeatletter 
\def\sec#1{\def\tempa{#1}\futurelet\next\[email protected]}% Save first argument 
\def\[email protected]{\ifx\next\bgroup\expandafter\[email protected]\else\expandafter\[email protected]\fi}%Check brace 
\def\[email protected]#1{\section*{\tempa\ and #1}}%Two args 
\def\[email protected]{\section*{\tempa}}%Single args 
\makeatother 

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

Я думал, что TeX понимает как параметры, соответствующие количеству первых «ящиков» после команды. этот «ящик» написан в фигурных скобках или это один символ. То есть. 'x^2 + 1' или' x^{2 + 1} ' Итак, у меня есть вопрос, ваша команда проверяет наличие фигурных скобок? Возможно ли создать команду LaTeX '\ sec': « A, b, c и d »для команды' \ sec {A} [b, c, d] ', « A и b »для' \ sec {A} [b] и "A" для '\ sec {A}'? – Crowley

+0

У вас есть два вопроса. 1) Да, моя команда проверяет наличие фигурных скобок. 2) Да, можно создать макрос для '\ sec {A} [b, c, d]' или '\ sec {A} [b]' или '\ sec {A}'. –

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

Все вышеперечисленное шоу трудно это может быть, чтобы сделать хороший, гибкий (или запретить перегруженный) функцию в LaTeX !!! (Что TeX код выглядит как греческие для меня)

ну просто добавить мое недавнее (хотя и не столь гибки) развитие, вот что я недавно использовал в своем дипломном документе, с

\usepackage{ifthen} % provides conditonals... 

Start команда, с «дополнительным» набор команд пустым по умолчанию:

\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 Робертсона, хотя, возможно, я попробую ...

+0

Мне нравится этот подход. Является более «программирующим» и, следовательно, более простым для чтения. Отличная работа! –

1

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

Смежные вопросы