Wie definiere ich eigene Kommandos?

Bitte nicht vor der Länge des Beitrages erschrecken ;-)

LaTeX stellt sehr viele Anweisungen zur Verfügung, die einem die Formatierung des Dokumentes erleichtern. Diese Vielfalt wird durch eine große Zahl von Paketen erweitert. Ob LaTeX oder Pakete, es ist nicht möglich alle Nutzerwünsche abzudecken. So kommt es sehr häufig vor, dass eigene Anweisungen definiert werden sollen.

In TeX selbst konnte das mittels \def realisiert werden. Diese Anweisung ist in LaTeX2e durch \newcommand bzw. \renewcommand erweitert bzw. ersetzt worden. Aber auch diese Anweisungen sind in ihrer Funktionalität sehr stark beschränkt. Das “neue” Paket xparse soll in diesem Post aufzeigen, wie einfach neue Definitionen mit verschiedensten Einstellungen möglich sind.

Bevor ich auf die neuen Möglichkeiten zu sprechen komme, möchte ich ein kurzes Resümee über die genannten Anweisungen geben. Allerdings sind zu Beginn einige Grundlagen zu legen.

Grundlagen

Im weiteren müssen wir zwischen optionalen und verpflichtenden Argumenten unterscheiden. Als Regel könnt ihr euch folgendes merken: Optionale Argumente werden durch das Klammerpaar [] angegeben. Verpflichtende Argumente werden durch das Klammerpaar {} angegeben. 

Ein weitere Grundlage ist etwas anglizistisch. Egal ob bei TeX oder LaTeX, es mussen zwischen long und nicht long arguments unterschieden werden. long sind Argumente, die einen Absatzumbruch enthalten dürfen, nicht long arguments dürfen es entsprechend nicht ;-) . Die Definition von long und nicht long arguments hat direkte Auswirkungen auf evtl. Fehlermeldungen, worauf wir aber im späteren eingehen.

Was macht \def?

Es ist bereits angesprochen worden, dass \def aus der TeX-Welt kommt. Die Syntax ist

\def\Anweisungen{Was soll die Anweisung tun}

Auch Argumente sind möglich, wobei die einfachste Form nur mittels verpflichtenden Argumenten auskommt.

\def\Anweisungen#1{Drucke die Eingabe fett \textbf{#1}}

Insgesamt sind 9 Argumente möglich, wobei keines als long deklariert ist. Möchte man die Argumente als long definieren, muss mit dem Prefix \long gearbeitet werden.

\long\def\Anweisungen#1{Drucke die Eingabe des long arguments #1}

Was macht \def noch? Es definiert die \Anweisung ohne vorher zu prüfen, ob die Anweisung existiert. Es wird also alles gnadenlos überschrieben.

Insgesamt lassen sich also folgende Punkte festhalten:

  1. Anweisungen werden nicht getestet, ob sie bereits existieren.
  2. Optionale Argumente sind nur mit Aufwand realisierbar.
  3. Alle Argumente sind per default keine long arguments.
  4. Es ist nicht möglich, Argumente separat als long bzw. nicht long zu definieren.

Was macht \newcommand bzw. \renewcommand?

Diese beiden Anweisungen sind durch LaTeX2e eingeführt worden und sollten bereits heute \def komplett ersetzen. Die allgemeine Syntax ist:

\newcommand{\Anweisungsname}{Was soll die Anweisung tun}

Für \renewcommand ist die Syntax äquivalent. Die Anweisung \newcommand testet, ob der gewünschte Befehlsname bereits existiert. Sollte dies der Fall sein, so wird eine entsprechende Fehlermeldung generiert. \renewcommand macht nun genau das Gegenteil. Es redefiniert eine existierende Anweisung. Sollte die Anweisung allerdings nicht existieren, so gibt es eine entsprechende Fehlermeldung. Somit ist durch die Einführung dieser beiden Anweisungen eine höhere Sicherheit gewährleistet, wobei durch \renewcommand der Nutzer explizit auf eine Redefinition hingewiesen wird bzw. diese erlauben muss.

Möchte man mit Argumenten arbeiten, kann die Anzahl der Argumente einfach in eckigen Klammern angegeben werden.

\newcommand{\Anweisungsname}[1]{Drucke die Eingabe fett \textbf{#1}}

Auch hier ist die Zahl der Argumente auf 9 limitiert. Allerdings erlauben die Anweisungen die Definition von einem optionalen Argument. welches stets mit #1 angesprochen wird.

\newcommand{\Anweisungsname}[2][default]{\textbf{#2} -- das optionale Argument ist: #1}

\Anweisungsname ist nun mit zwei Argumenten definiert, wobei das erste ein optionales Argument ist. Das Argument der zweiten eckigen Klammer wird hierbei als Defaultwert genommen, falls kein optionales Argument angegeben ist. In unserem Beispiel also “default”.

Die Anweisungen \newcommand bzw. \renewcommand definieren ihre Argumente stets als long. Möchte man dies nicht, so können die Sternvarianten der Anweisungen genutzt werden: \newcommand* bzw. \renewcommand*. Aber auch hier werden alle Argumente mit dem gleichen Typ versehen.

Fassen wir also zusammen:

  1. \newcommand testet, ob eine Anweisungen bereits existiert. Ist es der Fall, so gibt es einen Fehler.
  2. \renewcommand testet, ob eine Anweisungen bereits existiert und überschreibt diese. Ist die Anweisung unbekannt, gibt es einen Fehler.
  3. Die Anweisungen erlauben die Definition von einem optionalen Argument, welches stets das erste sein muss.
  4. Alle Argumente sind per default long arguments.
  5. Es ist nicht möglich, Argumente separat als long bzw. nicht long zu definieren.

Bevor wir zum Hauptteil und zum eigentlichen Paket xparse kommen, noch ein kleiner Exkurs.

Exkurs: Unterschied der Fehlermeldung bei long und nicht long.

Auf die Unterschiede zwischen long und nicht long bin ich bereits eingegangen. Jetzt ist auch die Frage berechtigt, warum es überhaupt diese Unterscheidung gibt bzw. was es für Vorteile hat, ein Makro als nicht long zu definieren. Hierzu nehmen wir ein Beispiel:

\documentclass{article}
%Definition als long
\newcommand\Anweisung[1]{Argument: \textbf{#1}}
\begin{document
}
%Klammer vergessen zuzumachen
\Anweisung{foo

\end{document
}

Die zugehörige Fehlermeldung lautet:

Runaway argument?
{foo \par \end {document}
! File ended while scanning use of \Anweisung.
<inserted text>
\par
<*> test.tex

Nutze ich hingegen die Definition \newcommand*\Anweisung[1]{Argument: \textbf{#1}} (also nicht long), so ist die Fehlermeldung:

Runaway argument?
{foo
! Paragraph ended before \Anweisung was complete.
<to be read again>
\par
l.22

Wie wir sehen, ist bei der nicht long Definition die entsprechende Zeilennummer angegeben. In unserem kleinen Beispiel macht das nicht viel aus, aber stellt euch größere Dokumente vor, bei denen die Anweisung  \Anweisung öfter aufgerufen wird. Ich denke es wird deutlich, dass bevorzugt Makros des Typs nicht long aguments genutzt werden sollte.

Definition von Kommandos mittels xparse?

xparse ist ein Paket und muss entsprechend geladen werden.

\usepackage{xparse}

xparse basiert auf LaTeX3. Dazu vielleicht in einem späteren Blog-Post ein wenig mehr.

Das Paket definiert verschiedenste Funktionen, um die Definition von neuen Anweisungen zu gewährleisten. Wir wollen uns hier auf die zwei wesentlichen Konzentrieren: \NewDocumentCommand und \RenewDocumentCommand.

Wie bereits im vorigen Abschnitt ausgeführt, lassen sich folgende Analogien feststellen. \NewDocumentCommand definiert eine Anweisung; sollte die Anweisung jedoch bereits existieren, so wird eine entsprechende Fehlermeldung generiert. Entsprechend ist \RenewDocumentCommand zu verstehen. Sollte die Anweisung nicht existieren, so gibt es eine Fehlermeldung. Nebenbei bemerkt haben die Entwickler von xparse auf verständlichere Fehlermeldungen geachtet.

Die vorgestellten Funktionen weichen von der Syntax und der Deklaration von Argumenten geringfügig zu den bereits vorgestellten Möglichkeiten ab. Aber dadurch ist eine höhere Flexibilität gegeben. Die Syntax ist:

\NewDocumentCommand{\Anweisung}{<Anweisungsspezifikation>}{Was soll getan werden}

Wir sehen also, dass insgesamt drei verpflichtende Argumente existieren. Die Argumentenspezifikation ist hier nicht gezeigt, weil diese einen extra Absatz bedarf.

Wie bereits in den vorherigen Ausführungen sind maximal 9 Argumente zulässig. Die Angabe der Argumente erfolgt nicht mit Zahlen, sondern mit definierten Buchstaben. Die Liste ist ziemlich lang, so dass ich hier nur zwei (eigentlich drei) wesentliche vorstelle.

Arg Erläuterung
m verpflichtendes Argument (engl.: mandatory)
o optionales Argument (engl.: optional), bei dem kein Defaultwert angegeben werden kann. Allerdings kann mittels \IfNoValue(TF) getestet werden, ob ein optionales Argument existiert.
O{} optionales Argument (engl.: optional), default wird in Klammern angegeben

Alle diese Argumenttypen sind von Hause aus als nicht long definiert. Möchte man ein Argument als long definieren, so muss ein + (plus) davor gesetzt werden. Um das erworbene Wissen zu nutzen, ein Beispiel. Die nachstehende Definition deklariert \Anweisung mit drei Argumenten, wobei das erste und dritte verpflichtend sind und das zweite optional ist. Zudem soll das dritte Argument als long deklariert sein. Das lässt sich nun wie folgt bewerkstelligen

\NewDocumentCommand{\Anweisung}{m O{} +m}%
{%
Argument 1: #1\\
Argument 2: #2\\
Argument 3: #3\\
}

Fassen wir zusammen:

  1. \NewDocumentCommand testet, ob eine Anweisungen bereits existiert. Ist es der Fall, so gibt es einen Fehler.
  2. \RenewDocumentCommand testet, ob eine Anweisungen bereits existiert und überschreibt diese. Ist die Anweisung unbekannt, gibt es einen Fehler.
  3. Die Anweisungen erlauben die Definition von mehreren optionalen Argumenten, wobei die Reihenfolge durch den Nutzer bestimmt wird.
  4. Alle Argumente sind per default nicht long arguments.
  5. Es ist möglich, Argumente separat als long bzw. nicht long zu definieren.

Das Paket bietet noch viele weitere Argumententypen und auch Tests der optionalen Argumente. Dieser kleine Blog soll euch einen ersten Einstieg geben, was alles möglich ist. Zum Abschluss dieses Abschnittes noch eine kleine Motivation für xparse. Es behebt einen Bug von \newcommand, der Nutzer schon lange ärgert. Das soll folgendes Beispiel zeigen.

\documentclass{article}
\usepackage{xparse}
\newcommand*\AnweisungAlt[2][]{Argument: \textbf{#1} -- !#2!}
\NewDocumentCommand\AnweisungNeu{O{} m }{Argument: \textbf{#1} -- !#2!}
\begin{document}
\AnweisungAlt[[Argument mit eckigen Klammern
]]{foobar}

\AnweisungNeu[[Argument mit eckigen Klammern]]{foobar}
\end{document
}

Einfach mal Kompilieren und die Ergebnisse vergleichen ;-)

Fazit

Die Anweisung von Nutzerkommandos ist von Begin an bedacht worden. Die Möglichkeiten sind aber erst in den letzten Jahren gewachsen und sicherer geworden. Mit der Einführung von xparse stehen dem Nutzer eine Mannigfaltigkeit von Optionen zur Verfügung, die eine Formatierung des Dokumentes erheblich vereinfachen. Der Blogpost kann leider nur einen kleinen Ausschnitt wiedergeben. Es sollte aber deutlich geworden sein, dass anstelle von \def oder \newcommand die Anweisung \NewDocumentCommand genutzt werden sollte. Um sich mit xparse vertraut zu machen, solltet ihr die Dokumentation konsultieren.

Quellen

  • LaTeX3 Team. xparse, 2013: CTAN xparse
  • Frank Mittelbach et al. Der LaTeX Begleiter, 2. Aufl., Pearson Studium, 2005.

28. Mai 2013 von Marco Daniel
Kategorien: LaTeX | Schlagwörter: , , , , , , , , | 9 Kommentare

Kommentare (9)

  1. Ein schöner Artikel, übersichtlich und informativ; weckt Interesse.

    Aber ist es nicht besser, die Dokumentation zu konsultieren? ;-)

    Glückauf!

    • Ja, ein wirklich schöner Artikel, aber deutlich überflüssig, da jede (La)TeX-Einführung nach den absoluten Basics als erstes \newcommand und Verwandte erklärt. Immerhin schön, dass auf xparse hingewiesen wurde; allerdings fehlen da noch die höheren Ebenen der in LaTeX3 vorgesehenen Befehlsmechanismen.

      • Hi Moss,

        wie die Einleitung sagt, der Artikel stellt xparse vor und motiviert die Verwendung. Die zu Beginn resümierten Grundlagen zu \newcommand & Co. können Fortgeschrittene natürlich übergehen – für den einsteigenden Leser kann das eine sehr gute Grundlage für das Artikelverständnis sein, ohne dass er in einer LaTeX-Einführung erst nach diesem Teil suchen muss.

    • Hi Thomas,

      soweit ich weiß, ist die Dokumentation zu xparse nur in Englisch. Zudem finde ich prima, wenn ein nützliches Paket anhand von Beispielen vorgestellt wird. Besser als “Wir reden nicht darüber, denn es gibt eine Dokumentation”. ;-)

      • Soweit ich weiß, bezieht sich Thomas’ „ist es nicht besser, die Dokumentation zu konsultieren?“ vor allem auf einen witzigen Wortverwechsler, den Marco im Text hatte, und den ich beim Korrekturlesen auch übersehen hatte.

  2. Das ist eine schöne Zusammenfassung. Eine Tabelle mit den Befehlen und ihren Eigenschaften wäre noch nett als Nachschlagewerk.

    Zwei Anmerkungen:
    1. Bei der Unterscheidung von \newcommand* und \newcommand wurde in den Beispielen beides Mal \newcommand* geschrieben.
    2. Das letzte Beispiel wäre noch eindrücklicher, wenn am Ende der Makrodefinitionen jeweils noch ein Sonderzeichen käme (ein Komma oder so), damit man sieht, dass im ersten Fall foobar gar nicht mehr vom Makro expandiert wird.

    • Hallo Patrick,

      danke für das Feedback. Habe die letzten 2 Anmerkungen eingearbeitet.

      Die vorgeschlagene Tabelle ist eine gute Idee, die ich gerne ergänzen kann.

      Gruß

  3. \AnweisungNeu[[Argument mit eckigen Klammern]{foobar}

    in dem Fall nützt dir auch xparse nichts. Wohingegen eine Definition mit \newcommand aber problemlos funktioniert!

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert