Додаткові аргументи LaTeX


132

Як створити команду з необов'язковими аргументами в LaTeX? Щось на зразок:

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

Тоді я можу так назвати

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

Відповіді:


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

26

Загальна ідея створення "необов'язкових аргументів" полягає в тому, щоб спочатку визначити проміжну команду, яка сканує вперед, щоб виявити, які символи з’являються далі в потоці токенів, а потім вставляє відповідні макроси для обробки аргументів, що надходять відповідно. Це може бути досить стомлюючим (хоча і не складно) за допомогою загального програмування TeX. LaTeX\@ifnextchar досить корисний для таких речей.

Найкраща відповідь на ваше запитання - використовувати новий xparseпакет. Він є частиною набору програмування LaTeX3 і містить широкі можливості для визначення команд з досить довільними необов'язковими аргументами.

У вашому прикладі у вас є \secмакрос, який приймає один або два дужки аргументу. Це буде реалізовано за xparseдопомогою наступного:

\ documentclass {article}
\ usepackage {xparse}
\ start {документ}
\ DeclareDocumentCommand \ sec {mg} {%
    {# 1%
        \ IfNoValueF {# 2} {і # 2}%
    }%
}
(\ сек {Привіт})
(\ сек {Привіт} {Привіт})
\ end {документ}

Аргумент { 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 містера Робертсона, хоча, можливо, я Спробую ...


Мені подобається такий підхід. Більш "подібний до програмування" і тому його легше читати. Хороша робота!
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} `?
Кроулі

У вас є два питання. 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 з необов'язковим аргументом


-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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.