xparse (\NewDocumentCommand)

Sobald ein Befehl mehrere optionale Argumente oder eine echte Sternvariante haben soll, skaliert das Argumentzählen von \newcommand nicht mehr. Die moderne Antwort ist \NewDocumentCommand: Es deklariert die *Art* jedes Arguments als Buchstabenfolge. Ursprünglich war das eine Funktion des Pakets xparse, heute gehört es zum LaTeX-Kernel. Diese Seite behandelt die Mini-Sprache der Argumentspezifikation und die Tests, mit denen geprüft wird, was der Nutzer tatsächlich angegeben hat.

Heute Teil des Kernels

Früher brauchte man \usepackage{xparse}, aber seit der LaTeX-Version vom Oktober 2020 lebt diese Mechanik im Kernel selbst. Befehle wie \NewDocumentCommand sind sofort verfügbar, und xparse muss selten geladen werden. Die Kerneldatei dafür heißt ltcmd, und das Paket xparse selbst wird offiziell als „obsolete“ bezeichnet. Von wenigen veralteten Argumenttypen abgesehen, kann neuer Code diese Befehle ohne Zusatzpaket verwenden.

Die Idee dieser Schnittstelle ist, Bedeutung, also Interface, von der Implementierung zu trennen. Die Argumentfolge, die Nutzer sehen — Pflichtargumente, Optionen, Stern — wird als Argumentspezifikation (arg-spec) deklariert; der Körper erhält die Argumente immer in normalisierter Form als #1, #2 usw. Die Grundlagen von \newcommand stehen auf der Seite „Makros definieren“; wer sie kennt, sieht den Unterschied leichter.

Befehle und Umgebungen definieren

Die Grundform ist \NewDocumentCommand{\cmd}{⟨arg-spec⟩}{⟨code⟩}: Befehlsname, Argumentspezifikation, Körper. Wie \newcommand hat es Geschwister für verschiedene Zwecke; der Unterschied ist, wie sie auf bereits definierte Namen reagieren.

BefehlBei vorhandenem Namen
\NewDocumentCommandFehler, wenn schon definiert
\RenewDocumentCommandFehler, wenn noch nicht definiert (arbeitet vorhandenen Befehl um)
\ProvideDocumentCommandDefiniert nur, wenn noch nicht vorhanden
\DeclareDocumentCommandÜberschreibt immer (sparsam verwenden)

Für Umgebungen gibt es dieselbe Mechanik mit \NewDocumentEnvironment{⟨env⟩}{⟨arg-spec⟩}{⟨start code⟩}{⟨end code⟩} (sowie \Renew…, \Provide…, \Declare…). Die Argumente werden nach \begin{⟨env⟩} gegeben und sind sowohl im Start- als auch im Endcode sichtbar; siehe die Seite „Eigene Umgebungen“. Ein Bonus: Alle so erzeugten Befehle sind automatisch robust, intern über e-TeXs \protected, sodass in Überschriften oder Beschriftungen kein \protect nötig ist.

Es gibt außerdem die expandierbare Variante \NewExpandableDocumentCommand. Sie funktioniert in Kontexten, in denen ein Befehl expandiert wird, etwa in \edef oder \write; dafür sind die erlaubten Argumenttypen eingeschränkt. Boolesche Tests wie s/t und Verbatim v stehen dort nicht zur Verfügung. Für gewöhnliche Dokumente ist die normale Form richtig.

Die Sprache der Argumentspezifikation

Eine Argumentspezifikation ist eine Zeichenkette, in der jeder Buchstabe den Typ eines Arguments benennt: pflichtig, optional, Stern, durch bestimmte Zeichen begrenzt usw. Jeder Typ kommt im Körper als #1, #2 usw. an; die wichtige Feinheit ist, dass ein nicht angegebenes optionales Argument einen besonderen Wert erhält. Die wichtigsten Typen stehen in der Tabelle.

TypSchreibweiseBedeutungAnkunft im Körper
mmPflichtargument {}Normales #1
ooOptionales [...]-Argument-NoValue-, wenn fehlend
OO{default}Optional mit Standardwertdefault, wenn fehlend
ssOptionaler Stern *\BooleanTrue / \BooleanFalse
tt⟨char⟩Optionales bestimmtes Zeichentoken\BooleanTrue / \BooleanFalse
rr⟨d1⟩⟨d2⟩Pflichtargument, begrenzt durch d1d2-NoValue- nach Fehler, wenn fehlend
dd⟨d1⟩⟨d2⟩Optional, begrenzt durch d1d2-NoValue-, wenn fehlend
ee{⟨tokens⟩}Verzierungen, z. B. ^, _Jeweils -NoValue-, wenn fehlend
vvVerbatim-ArgumentDie wörtlichen Zeichen

m ist das grundlegende Pflichtargument; es akzeptiert eine Klammergruppe oder ein einzelnes Token, und äußere {} werden entfernt, bevor der Körper es sieht. o ist das übliche optionale [...]-Argument, O{default} dasselbe mit Standardwert. Großbuchstabentypen wie O und D erlauben einen Standardwert; die Kleinbuchstaben o/d liefern stattdessen den Spezialmarker -NoValue-.

s erkennt einen führenden Stern *: vorhanden ergibt \BooleanTrue, fehlend \BooleanFalse. Die Verallgemeinerung auf ein einzelnes Zeichen ist t⟨char⟩; t+ meldet etwa das Vorhandensein von + als Bool. r⟨d1⟩⟨d2⟩ ist ein pflichtiges, von selbst gewählten Begrenzern eingeschlossenes Argument, etwa r() für runde Klammern; fehlt der öffnende Begrenzer, gibt es einen Fehler und -NoValue-. d⟨d1⟩⟨d2⟩ ist die optionale begrenzte Variante.

Etwas spezieller ist e{⟨tokens⟩}, das Verzierungen wie ^ und _ sammelt. Mit e{^_} nimmt es ^{...} und _{...} in beliebiger Reihenfolge auf; nicht angegebene Verzierungen werden -NoValue-. Die angegebenen Tokens müssen verschieden sein. v liest ein Verbatim-Argument ähnlich \verb. Bei begrenzten Typen wie r und d dürfen die TeX-Gruppierungszeichen { und } nicht als Begrenzer dienen; üblich sind natürlich gepaarte Zeichen wie [], () oder "".

Argumente prüfen: die Tests

Für optionale Argumente oder Sterne muss der Körper prüfen, ob etwas angegeben wurde. Dafür gibt es zwei Befehlsfamilien. \IfNoValueTF{#1}{⟨if no value⟩}{⟨if value⟩} prüft, ob das Argument -NoValue- ist, also fehlte: Fehlt es, läuft der erste Zweig, andernfalls der zweite. Die Umkehrung \IfValueTF existiert ebenfalls, ebenso Einzelzweigformen (\IfNoValueT / \IfNoValueF, \IfValueT / \IfValueF).

Für Boolesche Werte aus s oder t verwendet man \IfBooleanTF{#1}{⟨if starred⟩}{⟨if not⟩}. Ist #1 \BooleanTrue, läuft der erste Zweig; bei \BooleanFalse der zweite. Auch \IfBooleanT / \IfBooleanF gibt es. Faustregel: \IfNoValueTF und Verwandte sind für optionale Argumente wie o/d; \IfBooleanTF und Verwandte für Bool-Argumente aus s/t. Außerdem ist -NoValue- so gebaut, dass es nicht mit dem wörtlichen Text -NoValue- übereinstimmt; testen Sie es daher immer mit \IfNoValueTF.

Ein Beispiel: Stern plus Option mit Standard

Mit der Spezifikation s O{} m bauen wir einen Befehl mit Sternvariante und optionalem Argument mit Standard. Als Beispiel dient ein Überschriftenbefehl: #1 ist der Stern, geprüft mit \IfBooleanTF, #2 die optionale Kurzüberschrift mit leerem Standard, #3 die Hauptüberschrift.

latex
\NewDocumentCommand{\heading}{s O{} m}{%
  \IfBooleanTF{#1}%
    {\textbf{#3}}%                       星つき: 番号なしの見出し / starred: unnumbered
    {\section%
       \IfNoValueTF{#2}%
         {{#3}}%                          短縮見出しなし / no short title
         {[#2]{#3}}%                       短縮見出しあり / with short title
    }%
}

% 使用例 / usage
\heading{Introduction}             % 通常の番号つき節
\heading[Intro]{A Long Introduction} % 目次用に短縮見出しを指定
\heading*{Preface}                 % 星つき: 太字の無番号見出し

Eine Feinheit: Verwechseln Sie o und O{} nicht. Mit o wird ein nicht angegebenes Argument zu -NoValue-, also verzweigt man wie oben mit \IfNoValueTF. Mit O{} ist dagegen immer ein Wert vorhanden, leer wenn ausgelassen; dann prüft man auf Leere, etwa mit \tl_if_blank:nTF (expl3) oder \ifblank (etoolbox), nicht mit \IfNoValueTF. Im obigen Beispiel müsste das optionale Argument o ohne Standard sein, damit der \IfNoValueTF-Zweig wie beabsichtigt arbeitet.

Warum es \newcommand schlägt

\newcommand erlaubt nur ein optionales Argument, und zwar das erste, und bietet keine eingebaute Sternvariante. Klassisch schrieb man dafür Low-Level-Mechanik wie \@ifstar und \@ifnextchar von Hand; diese braucht \makeatletter, ist bei Leerraum und Schachtelung empfindlich und schlecht lesbar.

  • Mehrere unabhängige optionale Argumente (o o m, O{a} O{b} m usw.).
  • Echte Sternvarianten über s plus \IfBooleanTF, ohne \@ifstar-Trick.
  • Deklarative Standardwerte: O{default} legt den Wert bei Auslassung fest.
  • Von Anfang an robust: kein \protect in Überschriften oder Beschriftungen.
  • Eingabesyntaxen, die \newcommand nicht ausdrücken kann: begrenzte Argumente (r, d) und Verzierungen (e).

Kurz: Eine einfache Abkürzung ist mit \newcommand gut aufgehoben, aber sobald die Argumentstruktur nur etwas anspruchsvoller wird, ist \NewDocumentCommand die erste Wahl. Wenn der Körper danach als kleines Programm geschrieben werden soll, ist die Kombination mit expl3, der LaTeX3-Programmierschicht, der natürliche nächste Schritt. Für Klassen und Pakete siehe die Autorenseite.