Wenn ich in einem Befehl mit optionalen Argument im diesem eckige Klammern einsetze, erhalte ich seltsame Ergebnisse. Beispiel

\documentclass{article}
\begin{document}
\section[[Test]]{Test}
\end{document}

Ich habe durch ausprobieren herausgefunden, dass das Ergebnis ist, wie ich es eigentlich erwartet hätte, wenn ich zusätzlich { und } verwende:

\documentclass{article}
\begin{document}
\section[{[Test]}]{Test}
\end{document}

Wieso ist das so?

gefragt 24 Jun '13, 12:36

georg's gravatar image

georg
185447
Akzeptiert-Rate: 0%


Um das Warum zu verstehen, muss man eigentlich verstehen, was TeX (nicht LaTeX) für Argumente kennt und wie diese in LaTeX eingesetzt sind. TeX kennt grundsätzlich zwei Arten von Argumenten:

  1. unbegrenzte Argumente -- das sind die „normalen“ Argumente die in LaTeX mit { und } umschlossen sind.
  2. begrenzte Argumente -- das sind alle anderen Argumente. Was „begrenzt“ hier bedeutet, wird noch genauer erklärt.

Alle Makros, egal ob sie nun mit LaTeXs \newcommand definiert wurden oder nicht, werden schlussendlich eigentlich mit \def definiert. Die Syntax für unbegrenzte Argumente sieht folgendermaßen aus:

\def\foo#1#2{irgendwas mit #1 und #2}

Das definiert das Makro \foo mit zwei unbegrenzten Argumenten. Diese Argumente sind die nächsten zwei Token (= Charaktere oder Kontrollsequenzen) oder balancierten Gruppen, die dem Makro folgen:

\foo ab => #1=a und #2=b
\foo a\bla => #1=a und #2=\bla
\foo{ab}ab => #1=ab und #2=a
\foo{ab}{ab} => #1=ab und #2=ab
\foo\bar{\baz ab} => #1=\bar und #2=\bar ab
...

LaTeXs Syntax ist es, solche Argumente grundsätzlich mit geschweiften Klammern { und } zu umschließen. Dabei müssen die Klammern balanciert sein, was heißt, dass es zu jeder öffnenden Klammer auch eine schließende geben muss, und zwar auf gleicher Ebene. (Eigentlich müssen es nicht { und } sein sondern Charaktere mit catcodes 1 (Beginn einer Gruppe) und 2 (Ende einer Gruppe sein, unabhängig von ihrem Aussehen, aber das nur nebenbei).

Begrenzte Argumente werden z.B. so definiert:

\def\foo[#1]{irgenwas mit #1}

Das definiert \foo dergestalt, dass es nach Aufruf eine öffnende eckige Klammer erwartet. Kommt sie nicht als nächstes, gibt es einen Fehler. Wird sie gefunden, dann wird sie weggeworfen, und alles was nun folgt bis zur nächsten schließenden eckigen Klammer auf der selben Gruppierungsebene wird als Argument betrachtet. Wird die schließende eckige Klammer nicht gefunden, Wird sie gefunden, wird sie weggeworfen und alles, was dazwischen lag ist nun das Argument. Dabei wird eine eventuelle äußere Schicht von { und } entfernt:

\foo[bla] => #1=bla
\foo [bla] => #1=bla
\foo[bla{]}bla] => #1=bla{]}bla
\foo[{bla}] => #1=bla
\foo[{{bla}}] => #1={bla}
\foo x[] => Fehler, die öffnende Klammer [ wird nicht als erstes gefunden

Die Begrenzer müssten eckige Klammern sein, irgendwelche anderen Token (auch mehrere) gehen auch (abgesehen von ein paar Symbolen mit speziellen Kategoriecodes wie %, { und }).

\def\foo a#1b#2{irgendwas mit #1 und #2}

Hier ist das erste Argument begrenzt von a und b, das zweite ist unbegrenzt:

\foo abc => #1=<leer> #2=c
\foo aabbcc => #1=a #2=b; cc folgt im Input-Stream
\foo{aabbcc}{} => Fehler, da die Begrenzer fehlen (sind in der Gruppe versteckt)
\foo a{abbcc}b{xxx} => #1=abbcc #2=xxx

Ein solcher Argument-Typ steht auch hinter LaTeXs optionalen Argumenten:

\section[foo]{bar} => #1=foo #2=bar
\section[[foo]]{bar} => #1=[foo #2=]; {bar} bleibt danach im Input-Stream übrig
\section[{[foo]}]{bar} => #1=[foo] #2=bar

Das Paket xparse (oder genauer: seine Befehle \NewDocumentCommand, ...) definiert seine optionalen Argumente anders: solange die Klammern balanciert sind, muss man sie nicht mit extra geschweiften Klammern umschließen. Hier führen öffnende eckige Klammern nun zu einem Fehler, wenn die entsprechende schließende Klammer fehlt.

\foo[[]] => #1=[]
\foo[[] => Fehler
\foo[{[}] => #1={[}
\foo[]] => #1=<leer>; ] folgt im Input-Stream
\foo[{[]}] => #1=[]
Permanenter link

beantwortet 24 Jun '13, 18:24

cgnieder's gravatar image

cgnieder
22.1k243463
Akzeptiert-Rate: 60%

Das hängt aber alles mit \futurelet zusammen. LaTeX2e nutzt dieses Argument, um das optionale Argument zu ermitteln. xparse geht einen anderen weg.

(24 Jun '13, 18:51) Marco_D

@Marco \futurelet ist doch nur für die Optionalität der Argumente verantwortlich und hat mit der Frage nichts zu tun?

(24 Jun '13, 18:53) cgnieder

"unbegrenzte" Argumente müssen nicht unbedingt geklammert werden: \textbf A oder \newcommand\foo. Es gibt dann auch noch sowas: \def\foo#1\a#|\b#|...\c#2{...}, weshalb ich an deiner Stelle nicht so weit ausgeholt hätte, denn LaTeX kennt das alles nicht.

(24 Jun '13, 18:53) Herbert

@Herbert das habe ich beides erwähnt. Vielleicht war es etwas Overkill, für die Frage so weit auszuholen, wenn man aber den wirklichen Grund wissen will, muss man schon TeXs begrenzte Argumente kennen.

(24 Jun '13, 18:56) cgnieder

@Clemens: ich meine so etwa wie \def\foo#{...}, also ohne explizite Angabe der Parameter-Nummer. Ich sehe es nicht in deiner Antwort.

(24 Jun '13, 19:22) Herbert

@Herbert Ah, habe ich überlesen... stimmt, das hab ich tatsächlich absichtlich weggelassen, weil es für das Verständis, warum LaTeXs optionale Argumente anders funktionieren als die obligatorischen, nicht nötig ist.

(24 Jun '13, 19:26) cgnieder

@Clemens: Das ist immer das Problem, wenn man ordentlich "ausholt" ... :-).

(24 Jun '13, 19:37) Herbert
Ergebnis 5 von 7 show 2 more comments

Zur Ermittlung des Arguments wird einfach nach der schließenden Klammer ] gesucht und die erstbeste genommen. Du musst daher die Klammerung vorsehen, wenn das Argument selbst eine schließende Klammer enthält. Man könnte xparse nehmen, aber das macht Probleme wenn man eine zusätzliche öffnende Klammer [ verwendet.

Permanenter link

beantwortet 24 Jun '13, 13:22

Herbert's gravatar image

Herbert
5.1k34
Akzeptiert-Rate: 31%

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:

×7
×7
×2

gestellte Frage: 24 Jun '13, 12:36

Frage wurde gesehen: 11,964 Mal

zuletzt geändert: 24 Jun '13, 19:40