Meines Wissens nach erlaubt \newcommand{\name}[x][default_1]{definition} bei einer Befehlsdefinition über [x][default_1] die Definition eines Befehls mit x Argumenten, wobei man nur für das erste einen Defaultwert angeben kann.

Hier mal ein konkretes Beispiel:

Open in writeLaTeX
\documentclass{article}

\newcommand{\name}[3][Herr]{\textbf{#1}~\textsc{#2}~\textit{#3}}

\begin{document}

\name[Frau]{Maria}{Musterfrau}

\name{Max}{Mustermann}

\end{document}

Könnte man als hier auch für #2 und #3 Defaultwerte vorgeben?

gefragt 12 Aug '14, 17:10

feynman's gravatar image

feynman
1.0k132937
Akzeptiert-Rate: 23%

bearbeitet 12 Aug '14, 17:37

cgnieder's gravatar image

cgnieder
22.1k253463


Meines Wissens nach erlaubt \newcommand{\name}[x][default_1]{definition} bei einer Befehlsdefinition über [x][default_1] die Definition eines Befehls mit x Argumenten, wobei man nur für das erste einen Defaultwert angeben kann.

Stimmt, wobei x nicht größer als 9 sein kann. Die maximale Anzahl von neun Argumenten ist durch TeX vorgegeben und kann nicht umgangen werden. Sollte man je auf ein Makro mit mehr Argumenten treffen, dann täuscht es das nur vor (und wurde höchstwahrscheinlich schlecht designt: wer kann sich schon bei so vielen Argumenten die richtige Reihenfolge merken? Ich hab bei 4 schon Schwierigkeiten...).

Mit \newcommand lassen sich nur Befehle mit maximal einem optionalen Argument an der ersten Stelle definieren. Dass es natürlich auch anders geht, beweisen schon die zwei Makros, die wir alle jede Woche viele Dutzend mal tippen:

Open in writeLaTeX
\documentclass[<Optionen>]{<Klasse>}[<Version>]
\usepackage[<Optionen>]{<Pakete>}[<Version>]

Es gibt eine Reihe von Wegen, wie man derartige Makros definieren kann, sehr bequem geht es mit dem Paket xparse (wenn gewünscht füge ich gerne die Methode „von Hand“ zu meiner Antwort hinzu...):

Open in writeLaTeX
\usepackage{xparse}
\NewDocumentCommand\foo{O{}mO{bar}}{%
  `#1' (optional, Default leer)
  `#2' (benötigt)
  `#3' (optional, Default: `bar')%
}

Die Argumente werden im zweiten Argument von \NewDocumentCommand spezifiziert,

Open in writeLaTeX
\NewDocumentCommand{<Befehl>}{<Argumente>}{<Definition>}

und zwar stehen bestimmte Buchstaben für bestimmte Typen von Argumenten. Ich will nicht alle aufzählen (dafür gibt es die Doku) sondern drei heraussuchen:

  • m (mandatory): normales nicht-optionales Argument.
  • o (optional): ein optionales Argument ohne Default-Wert. Ob es angegeben wurde, lässt sich mit \IfNoValueTF{#1}{<wahr>}{<falsch>} testen. Ein leeres aber vorhandenes Argument (wie etwa \foo[] würde hier <falsch> geben, da »leer« eben nicht das gleiche wie »nicht vorhanden« ist.
  • O{<default>} (optional): ein optionales Argument, dem man in geschweiften Klammern einen Default-Wert geben kann.

Ich würde allerdings einen Befehl mit drei optionalen Argumenten vermeiden: kommen sie hintereinander, dann kann man die folgenden nur verwenden, wenn man die vorhergehenden auch setzt:

Open in writeLaTeX
\foo[][bar] % das erste leer aber gesetzt, das zweite `bar'

Das Interface von xparse erlaubt auch Befehle mit anderen Klammern als der eckigen und geschweiften, es lassen sich auch Argumente mit geschweiften Klammern leicht optional machen. Bevor man sich damit aber austobt, sollte man sich besser überlegen, ob es sinnvoll ist, von der allgemeinen LaTeX-Praxis abzuweichen, und falls ja: warum.


Um die Frage nach den Default-Werten für die anderen Argumente des Makros in der Fragestellung zu beantworten: man könnte darauf testen, ob die Argumente 2 und 3 etwas enthalten außer Leerzeichen und falls nicht, entsprechenden Text vorgeben. Für solche Tests mag ich das Paket etoolbox recht gerne:

Open in writeLaTeX
\documentclass{article}
\usepackage{etoolbox}

\newcommand{\name}[3][Herr]{%
  \textbf{#1}~%
  \textsc{\ifblank{#2}{Bitte Vornamen angeben!}{#2}}~%
  \textit{\ifblank{#2}{Bitte Nachnamen angeben!}{#3}}%
}

\begin{document}
\name{}{}
\end{document}

alt text

Permanenter link

beantwortet 12 Aug '14, 18:04

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 16 Aug '14, 17:13

Epllus's gravatar image

Epllus
620269

Danke für die ausführliche Antwort. Das Paket xparse passt für den Anwendungsfall, den ich im hinterkopf habe.

(12 Aug '14, 18:18) feynman

@Clemens Dein Einwand "...wer kann sich schon bei so vielen Argumenten die richtige Reihenfolge merken?" ist natürlich berechtigt. Praktisch wäre es, wenn man Argumente über keys, z.B. in der Form \name[anrede=Herr,nachname=Mustermann,vorname=Max] übergeben könnte. Das geht doch bestimmt auch irgendwie, wie man am Beispiel von tikz z.B. sieht.

(12 Aug '14, 19:16) feynman

Klar, das geht. Dafür gibt es eine Reihe von Methoden. Unter anderem kann man das key-System von TikZ verwenden, das Du erwähnst.

(12 Aug '14, 19:19) cgnieder

@Clemens Sollte man diese Variante hier diskutieren oder eventuell eine neue Frage hierzu formulieren?

(12 Aug '14, 19:35) feynman

Das scheint mir für eine neue Frage besser geeignet zu sein. Da könnten dann vielleicht auch mehrere Antworten mit verschiedenen techniken gegeben werden

(12 Aug '14, 20:06) cgnieder
Ergebnis 5 von 6 show 1 more comments

Als ich die Frage las, kam mir direkt ein key-value system in den Sinn (wie Du auch in einem Kommentar hier vorgeschlagen hast).

Das koennte so aussehen:

Open in writeLaTeX
\documentclass{article}

\usepackage{pgfkeys}

\pgfkeys{
    % dies DEKLARIERT keys mit dem angegebenen initial wert.
    %  der suffix '/.initial' heisst "legen neuen Key mit dem
    %  angegeben Wert an".
    /feynman/anrede/.initial=,
    /feynman/name/.initial=,
    /feynman/vorname/.initial=,
}

\newcommand{\name}[1]{%
    \begingroup
    % Dies nimmt die key-value-liste #1 und setzt alle keys.
    % Wenn jemand "anrede" schreibt, wird automatisch "/feynman/"
    % davor gehaengt:
    \pgfqkeys{/feynman}{#1}%
    %
    % hier hoelen wir Werte ab und speichern sie in Makros:
    \pgfkeysgetvalue{/feynman/anrede}\feynmanAnrede
    \pgfkeysgetvalue{/feynman/name}\feynmanName
    \pgfkeysgetvalue{/feynman/vorname}\feynmanVorname
    %
    % Nun kann man was damit machen - z.B. mithilfe von TeX
    % Programmierung:
    \ifx\feynmanAnrede\empty
    \else
        \textbf{\feynmanAnrede}~%
    \fi
    %
    \ifx\feynmanVorname\empty
        \PackageError{feynman}{Vorname fehlt}{}%
    \else
        \textsc{\feynmanVorname}~%
    \fi
    %
    \textit{\feynmanName}%
    \endgroup
}

\begin{document}

\name{anrede=Frau, vorname=Maria, name=Musterfrau}%

\name{vorname=Max, name=Mustermann}

\end{document}

alt text

Ist das zu laenglich? Naja, hier haette es ein deutlich einfacheres Makro nun auch getan! Allerdings hoert sich Deine Anwendung stark nach sowas wie einem serienbrief an - und da hat man zwei besondere Eigenschaften:

  1. es werden mit der Zeit immer mehr Eigenschaften, die dazu kommen
  2. man hat mehr oder weniger komplizierte Regeln, wann eine Eigenschaft angezeigt werden kann und wann es einen Fehler geben sollte.

Das habe ich hier ein bisschen angenommen und daher im code etwas ausfuehrlicher geschrieben.

Details zu dem Stichwort "TeX Programmierung" habe ich mal zusammengeschrieben, man findet das - zusammen mit weiterfuehrenden Hinweisen zu pgfkeys bspw. unter http://tex.stackexchange.com/questions/12668/where-do-i-start-latex-programming/27589#27589

Permanenter link

beantwortet 15 Aug '14, 22:28

cfeuersaenger's gravatar image

cfeuersaenger
3.7k23
Akzeptiert-Rate: 34%

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×52
×7

gestellte Frage: 12 Aug '14, 17:10

Frage wurde gesehen: 14,063 Mal

zuletzt geändert: 16 Aug '14, 17:13