Argumenty opcjonalne LaTeX

Odpowiedzi:

180

Przykład z przewodnika :

\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.
miku
źródło
23
Myślę, że chodziło o to, jak określić, czy podano opcjonalny argument, a nie domyślny.
Konrad Rudolph
45
Chociaż to prawda, znalazłem to pytanie, szukając sposobu na podanie domyślnego argumentu, więc ta odpowiedź była dla mnie najbardziej przydatna.
Tanner Swett
26

Ogólną ideą tworzenia „argumentów opcjonalnych” jest najpierw zdefiniowanie polecenia pośredniego, które skanuje naprzód, aby wykryć, jakie znaki pojawią się jako następne w strumieniu tokenów, a następnie wstawia odpowiednie makra, aby odpowiednio przetworzyć nadchodzące argumenty. Może to być dość żmudne (choć nie trudne) przy użyciu ogólnego programowania TeX. LaTeX \@ifnextcharjest całkiem przydatny do takich rzeczy.

Najlepszą odpowiedzią na Twoje pytanie jest skorzystanie z nowego xparsepakietu. Jest częścią pakietu programowania LaTeX3 i zawiera rozbudowane funkcje definiowania poleceń z dość dowolnymi opcjonalnymi argumentami.

W twoim przykładzie masz \secmakro, które przyjmuje jeden lub dwa argumenty stężone. Zostałoby to zaimplementowane przy użyciu xparse:

\ documentclass {artykuł}
\ usepackage {xparse}
\ begin {document}
\ DeclareDocumentCommand \ sec {mg} {%
    {# 1%
        \ IfNoValueF {# 2} {i # 2}%
    }%
}
(\ sec {Cześć})
(\ sec {Cześć} {Cześć})
\ end {document}

Argument { m g }definiuje argumenty \sec; moznacza „argument obowiązkowy” i gjest „opcjonalnym argumentem napiętym”. \IfNoValue(T)(F)można następnie użyć do sprawdzenia, czy drugi argument był rzeczywiście obecny, czy nie. Zobacz dokumentację dla innych typów opcjonalnych argumentów, które są dozwolone.

Will Robertson
źródło
4
Będzie! To nie działa. (Hello and ) (Hello and Hi)
Wynik
Dzięki za opinię, Alexey. Podejrzewam, że używasz starszej wersji xparse; ostatnio wykonano nad tym dużo pracy. Właśnie ukazał się TeX Live 2009 :)
Will Robertson
24

Wszystko to pokazuje, że ciężko jest stworzyć ładną, elastyczną (lub zabronić przeciążonej) funkcji w LaTeX !!! (ten kod TeX wygląda dla mnie jak grecki)

cóż, żeby dodać mój niedawny (aczkolwiek nie tak elastyczny) rozwój, oto czego ostatnio użyłem w mojej pracy doktorskiej, z

\usepackage{ifthen}  % provides conditonals...

Uruchom polecenie, domyślnie ustawiane jako puste polecenie „opcjonalne”:

\newcommand {\figHoriz} [4] []  {

Następnie każę makro ustawić zmienną tymczasową \ temp {}, w różny sposób w zależności od tego, czy opcjonalny argument jest pusty. Można to rozszerzyć na dowolny przekazany argument.

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

Następnie uruchamiam makro przy użyciu zmiennej \ temp {} w dwóch przypadkach. (Tutaj po prostu ustawia krótki podpis tak, aby był równy długiemu podpisowi, jeśli nie został określony przez użytkownika).

\begin{figure}[!]
    \begin{center}
        \includegraphics[width=350 pt]{#3}
        \temp   %see above for caption etc.
        \label{#2}
    \end{center}
\end{figure}
}

W tym przypadku sprawdzam tylko pojedynczy, „opcjonalny” argument, który dostarcza \ newcommand {}. Gdybyś miał ustawić to dla, powiedzmy, 3 "opcjonalnych" argumentów, nadal musiałbyś wysłać 3 puste argumenty ... np.

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

co jest dość głupie, wiem, ale to mniej więcej na tyle, na ile mam zamiar posunąć się do LaTeX-a - po prostu nie jest to aż tak sensowne, kiedy zacznę patrzeć na kod TeX-a ... Podoba mi się jednak metoda xparse pana Robertsona, być może ja spróbuję ...

Demis
źródło
Podoba mi się to podejście. Jest bardziej „programistyczny” i dlatego jest bardziej czytelny. Dobra robota!
kochany.by.Jezus
11

Wszystko, czego potrzebujesz, to:

\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
Alexey Malistov
źródło
Myślałem, że TeX rozumie jako parametry odpowiednią liczbę pierwszych „pudełek” po poleceniu. to „pudełko” jest zapisane w nawiasach klamrowych lub jest to jeden symbol. To znaczy. x^2+1lub x^{2+1} Mam pytanie, czy twoje polecenie sprawdza obecność szelek? Czy jest możliwe utworzenie polecenia LaTeX, które będzie \secdawało: „A, b, c i d” dla polecenia \sec{A}[b,c,d], „A i b” dla \sec{A}[b] and "A" for \ sec {A} `?
Crowley
Masz dwa pytania. 1) Tak, moje polecenie sprawdza obecność szelek. 2) Tak, jest możliwe utworzenie makra dla \sec{A}[b,c,d]lub \sec{A}[b]lub \sec{A}.
Alexey Malistov
6

Miałem podobny problem, gdy chciałem utworzyć polecenie, \dxaby skrócić \;\mathrm{d}x(tj. Wstawić dodatkową spację przed różniczką całki i ustawić „d” w pozycji pionowej). Ale chciałem też uczynić go na tyle elastycznym, aby zawierał zmienną integracji jako opcjonalny argument. W preambule umieściłem następujący kod.

\usepackage{ifthen}

\newcommand{\dx}[1][]{%
   \ifthenelse{ \equal{#1}{} }
      {\ensuremath{\;\mathrm{d}x}}
      {\ensuremath{\;\mathrm{d}#1}}
}

Następnie

\begin{document}
   $$\int x\dx$$
   $$\int t\dx[t]$$
\end{document}

daje \ dx z opcjonalnym argumentem

csar
źródło
-1

Oto moja próba, ale nie jest dokładnie zgodna z twoimi specyfikacjami. Nie w pełni przetestowany, więc bądź ostrożny.

\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
źródło