2009-11-28 21 views
88

Come si crea un comando con argomenti opzionali in LaTeX? Qualcosa di simile:Argomenti opzionali LaTeX

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

Poi, posso chiamarla come

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

questione rilevante: [definizioni comando diverso con e senza argomento opzionale] (http://tex.stackexchange.com/q/308/1347) . –

risposta

111

Esempio dal 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

Penso che la domanda riguardasse come determinare * se * è stato fornito un argomento opzionale, non fornendo un valore predefinito. –

+28

Anche se è vero, ho trovato questa domanda mentre cercavo un modo per fornire un argomento predefinito, quindi questa risposta è stata la più utile per me. –

18

L'idea generale dietro la creazione di "argomenti opzionali" è quello di definire prima un comando intermedio che analizza in avanti per rilevare quali caratteri verranno visualizzati successivamente nel flusso di token e quindi inserisce le macro rilevanti per elaborare gli argomenti in arrivo come appropriato. Questo può essere piuttosto noioso (anche se non difficile) utilizzando la programmazione generica di TeX. \@ifnextchar di LaTeX è abbastanza utile per cose del genere.

La migliore risposta per la tua domanda è utilizzare il nuovo pacchetto xparse. Fa parte della suite di programmazione LaTeX3 e contiene numerose funzionalità per la definizione dei comandi con argomenti facoltativi piuttosto arbitrari.

Nell'esempio si ha una macro \sec che accetta uno o due argomenti rinforzati. Questo sarebbe essere implementato usando xparse con la seguente:

 
\documentclass{article} 
\usepackage{xparse} 
\begin{document} 
\DeclareDocumentCommand\sec{ m g }{% 
    {#1% 
     \IfNoValueF {#2} { and #2}% 
    }% 
} 
(\sec{Hello}) 
(\sec{Hello}{Hi}) 
\end{document} 

L'argomento { m g } definisce gli argomenti di \sec; m significa "argomento obbligatorio" e g è "argomento rinforzato opzionale". \IfNoValue(T)(F) può quindi essere utilizzato per verificare se il secondo argomento fosse effettivamente presente o meno. Vedere la documentazione per gli altri tipi di argomenti facoltativi consentiti.

+4

Will! Non funziona. Uscita: '(Ciao e) (Ciao e Ciao)' –

+0

Grazie per il feedback, Alexey. Sospetto che tu stia utilizzando una versione precedente di xparse; c'è stato molto lavoro su di esso di recente. TeX Live 2009 è stato appena rilasciato :) –

12

Tutto ciò che serve è il seguente:

\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

Ho pensato che TeX comprendesse come parametri il conteggio appropriato delle prime 'caselle' dopo il comando. questa 'scatola' è scritta in parentesi graffe o è un simbolo. Vale a dire. 'x^2 + 1' o' x^{2 + 1} ' Quindi ho una domanda, il tuo comando verifica la presenza di parentesi graffe? È possibile creare il comando LaTeX '\ sec' producendo: " A, b, c e d "per il comando' \ sec {A} [b, c, d] ', " A e b "per' \ sec {A} [b] e "A" per '\ sec {A}'? – Crowley

+0

Hai due domande. 1) Sì, il mio comando verifica la presenza di parentesi graffe. 2) Sì, è possibile creare macro per '\ sec {A} [b, c, d]' o '\ sec {A} [b]' o '\ sec {A}'. –

-1

Ecco il mio tentativo, che non segue esattamente le caratteristiche del tuo però. Non completamente testato, quindi sii cauto.

\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

Tutto lo spettacolo sopra sia difficile può essere quello di fare una bella, flessibile (o vietare un sovraccarico) funzione in LaTeX !!! (Che il codice TeX assomiglia greco a me)

bene, solo per aggiungere il mio recente (anche se non così flessibile) di sviluppo, ecco quello che ho utilizzato di recente nella mia tesi doc, con

\usepackage{ifthen} % provides conditonals... 

Inizio il comando, con il comando "optional" insieme in bianco per impostazione predefinita:

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

ho poi la macro impostare una variabile temporanea, \ temp {}, in modo diverso a seconda se l'argomento opzionale è vuoto. Questo potrebbe essere esteso a qualsiasi argomento passato.

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

Poi eseguire la macro utilizzando il \ temp {variabile} per i due casi. (Qui imposta semplicemente il sottotitolo per pareggiare la didascalia lunga se non è stato specificato dall'utente).

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

In questo caso, controllo solo il singolo argomento "facoltativo" fornito da \ newcommand {}. Se dovessi configurarlo per, diciamo, 3 argomenti "facoltativi", dovresti comunque inviare i 3 argomenti vuoti ... ad es.

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

che è abbastanza stupido, lo so, ma questo è quanto ho intenzione di andare con LaTeX - non è solo che sensical una volta che iniziare a guardare il codice TeX ... mi piace Mr. metodo xparse di Robertson, però, forse ci proverò ...

+0

Mi piace questo approccio. È più "simile alla programmazione" e quindi più facile da leggere. Buon lavoro! –

1

ho avuto un problema simile, quando ho voluto creare un comando, \dx, per abbreviare \;\mathrm{d}x (vale a dire mettere uno spazio aggiuntivo prima che il differenziale del integrale e avere la "d" verticale pure). Ma poi volevo anche renderlo abbastanza flessibile da includere la variabile di integrazione come argomento opzionale. Ho inserito il seguente codice nel preambolo.

\usepackage{ifthen} 

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

Poi

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

\dx with optional argument