3
4

Hier wurde eine ähnliche Frage schon gestellt, mit folgendem 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}

Nachteil dieser Art von Befehlsdefinition ist unter anderem, dass man sich Art und Reihenfolge der Argumente merken muss. Könnte man den gezeigten Befehl auch so definieren, dass die Argumente in folgender Form übergeben werden?

Open in writeLaTeX
\name[anrede=Herr,nachname=Mustermann,vorname=Max]

gefragt 12 Aug '14, 20:15

feynman's gravatar image

feynman
1.0k132937
Akzeptiert-Rate: 23%

bearbeitet 12 Aug '14, 20:46

cgnieder's gravatar image

cgnieder
22.1k253463

Neben den bereits genannten gibt es u. a. auch noch kvsetkeys und kvoptions. Ich habe beide bisher nicht verwendet, weshalb ich auch keine Beispiele dafür erstellen kann. Siehe auch das CTAN-Topic key­val.

(13 Aug '14, 21:06) gast3

Eine weitere Methode ist das Paket xkeyval. Das Paket ist eine Erweiterung von keyval, einem Paket, das zum required-Teil einer TeX-Distribution gehört und z.B. von KOMA-Script oder graphicx verwendet wird. Der Standardbefehl zur Definition von Keys ist hier

Open in writeLaTeX
\define@key{<Familie>}{<Key>}[<Leerwert>]{<Code>}

Und wird in dieser Form auch von keyval bereitgestellt. xkeyval erweitert den Befehl um ein weiteres optionales Argument , auf das ich aber nicht weiter eingehen will:

Open in writeLaTeX
\define@key[<Präfix>]{<Familie>}{<Key>}[<Leerwert>]{<Code>}

Setzen kann man sie dann später mit

Open in writeLaTeX
\setkeys{<Familie>}{<Keys>}

Das folgende Beispiel bastelt mein Beispiel aus der Antwort mit pgfkeys nach und verwendet keyval, der Output ist der gleiche. Auch hier werden die Keys in einer Gruppe gesetzt, damit die Werte nur für den aktuellen Gebrauch gesetzt werden.

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

\makeatletter
\newcommand*\name@anrede{Herr/Frau}
\newcommand*\name@vorname{Vorname}
\newcommand*\name@nachname{Nachname}

\define@key{name}{anrede}  {\renewcommand*\name@anrede{#1}}
\define@key{name}{vorname} {\renewcommand*\name@vorname{#1}}
\define@key{name}{nachname}{\renewcommand*\name@nachname{#1}}

\newcommand*\name[1][]{%
  \begingroup
    \setkeys{name}{#1}%
    \name@anrede\ \name@vorname\ \name@nachname
  \endgroup
}

\makeatother
\begin{document}

\name\par
\name[anrede=Frau,nachname=Musterfrau,vorname=Mia]\par
\name

\end{document}

Mit xkeyval lässt sich das ganze etwas verkürzen. xkeyval kennt z.B. \define@cmdkey, bei dem der Wert in einem Makro gespeichert wird, das notfalls neu definiert wird.

Open in writeLaTeX
\define@cmdkey[<Präfix>]{<Familie>}[<Befehl-Präfix>]{<Name>}{<Code>}

Das definierte Makro bekommt den Namen \<Befehl-Präfix><Name> oder – wenn <Befehl-Präfix> nicht vorgegeben wird – \cmd<Präfix>@<Familie>@<Name> . Damit wird aus dem Beispiel:

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

\makeatletter
\newcommand*\name@anrede{Herr/Frau}
\newcommand*\name@vorname{Vorname}
\newcommand*\name@nachname{Nachname}

\define@cmdkey{name}[name@]{anrede}  {}
\define@cmdkey{name}[name@]{vorname} {}
\define@cmdkey{name}[name@]{nachname}{}

\newcommand*\name[1][]{%
  \begingroup
    \setkeys{name}{#1}%
    \name@anrede\ \name@vorname\ \name@nachname
  \endgroup
}

\makeatother
\begin{document}

\name\par
\name[anrede=Frau,nachname=Musterfrau,vorname=Mia]\par
\name

\end{document}

Definiert man die Makros vorher nicht selber, so kann man bei beiden Methoden durch Testen, ob das entsprechende Makro existiert, auch auf einfache Weise Fehlermeldungen oder anderes Verhalten etc. erreichen:

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

\makeatletter
\define@cmdkey{name}[name@]{anrede}  {}
\define@cmdkey{name}[name@]{vorname} {}
\define@cmdkey{name}[name@]{nachname}{}

\newcommand*\name[1][]{%
  \begingroup
    \setkeys{name}{#1}%
    \@ifundefined{name@anrede}
      {Herr/Frau}
      {\name@anrede}
    \@ifundefined{name@vorname}
      {Vorname}
      {\name@vorname}
    \@ifundefined{name@nachname}
      {Nachname}
      {\name@nachname}%
  \endgroup
}

\makeatother
\begin{document}

\name\par
\name[anrede=Frau,nachname=Musterfrau,vorname=Mia]\par
\name

\end{document}
Permanenter link

beantwortet 12 Aug '14, 21:30

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 20 Aug '14, 12:14

@Ijon hast Du da eine Referenz? Wenn da so ist, sollte man das als Caveat in die Antwort mit aufnehmen

(13 Aug '14, 23:18) cgnieder

Hinweis: diese Antwort stammt eigentlich aus der Originalfrage http://texwelt.de/wissen/fragen/8404/ist-es-moglich-eigene-befehle-mit-mehr-als-einem-optionalen-argument-zu-definieren. Ich poste sie hier in einer modifizierten Kopie, damit wir die Knowledge-Base leichter lesbar haben.


Ich schlage folgende Variante mit pgfkeys vor.

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

Diese Variante unterscheidet sich von der anderen hier vorgestellten dadurch, dass sie die Werte "direkt" in den Key speichert anstelle noch ein extra-makro zu verwenden. Vorteil (neben vernachlaessigbaren Speichereinsparungen): man kann dann auch sowas wie \pgfkeys{/feynman/name/.add={<prefix>}{<suffix>} machen, um einen existierenden Wert zu veraendern. Ausserdem erleichtert das das Auslesen der Werte fuer Leute, nicht auf Anhieb wissen wie das keyvalue system implementiert ist. Mit einem Wort: fuer keys, die nur Werte enthalten, empfehle ich die Deklaration mit /.initial wie oben beschrieben - das skaliert und ist leichter zu dokumentieren.

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 16 Aug '14, 10:43

cfeuersaenger's gravatar image

cfeuersaenger
3.7k23
Akzeptiert-Rate: 34%

bearbeitet 16 Aug '14, 10:44

Das KOMA-Script Paket scrbase stellt ebenfalls eine Schnittstelle für keyval-Optionen bereit. Dafür lädt es seinerseits das Paket keyval. Wenn ich die Anleitung von scrbase richtig verstehe, zielt die Schnittstelle zwar vornehmlich auf Paketautoren ab, sie lässt sich aber auch im Dokument verwenden.

Dazu muss man zunächst eine Schlüssel-Familie definieren

Open in writeLaTeX
\DefineFamily{<Familie>}

und das aktuelle Paket (hier: das Dokument) dieser Familie zuweisen:

Open in writeLaTeX
\DefineFamilyMember{<Familie>}

Danach kann man mit

Open in writeLaTeX
\DefineFamilyKey{<Familie>}{<Schlüssel>}{<Code>}

Schlüssel-Optionen definieren. Ausgeführt werden die Optionen dann mit

Open in writeLaTeX
\FamilyExecuteOptions{<Famlilie>}{<Keys>}

Genauer beschrieben ist das im scrguide.

Das folgende Beispiel bastelt das Beispiel aus meiner Antwort mit pgfkeys nach, das Ergebnis ist das ist gleiche. Auch hier werden die Optionen in einer Gruppe ausgeführt, um das Setzen lokal zu halten.

Open in writeLaTeX
\documentclass{scrartcl}
% \usepackage{scrbase}% ohne KOMA-Script-Klasse benötigt

\makeatletter
\newcommand*\name@anrede{Herr/Frau}
\newcommand*\name@vorname{Vorname}
\newcommand*\name@nachname{Nachname}

\DefineFamily{name}
\DefineFamilyMember{name}
\DefineFamilyKey{name}{anrede}  {\renewcommand*\name@anrede{#1}}
\DefineFamilyKey{name}{vorname} {\renewcommand*\name@vorname{#1}}
\DefineFamilyKey{name}{nachname}{\renewcommand*\name@nachname{#1}}

\newcommand*\name[1][]{%
  \begingroup
    \FamilyExecuteOptions{name}{#1}%
    \name@anrede\ \name@vorname\ \name@nachname
  \endgroup
}

\makeatother
\begin{document}

\name\par
\name[anrede=Frau,nachname=Musterfrau,vorname=Mia]\par
\name

\end{document}
Permanenter link

beantwortet 13 Aug '14, 15:44

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

Eine Möglichkeit ist es, das Paket pgfkeys zu verwenden, das den Options-Mechanismus für TikZ/PGF definiert. Beschrieben ist es im TikZ-Handbuch unter Utilities/Key Management. EIn kleines Beispiel demonstriert die wesentlichen Punkte:

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

\makeatletter
\pgfkeys{
  name/.cd ,% Pfad eindeutig für Befehl machen
    anrede/.code   = \renewcommand*\name@anrede{#1} ,
    vorname/.code  = \renewcommand*\name@vorname{#1} ,
    nachname/.code = \renewcommand*\name@nachname{#1} ,
}

\newcommand*\name@anrede{Herr/Frau}
\newcommand*\name@vorname{Vorname}
\newcommand*\name@nachname{Nachname}

\newcommand*\name[1][]{%
  \begingroup
    \pgfqkeys{/name}{#1}%
    \name@anrede\ \name@vorname\ \name@nachname
  \endgroup
}

\makeatother
\begin{document}

\name\par
\name[anrede=Frau,nachname=Musterfrau,vorname=Mia]\par
\name

\end{document}

alt text

Das Beispiel definiert Keys, die alle zum Pfad /name gehören. In Paketen habe ich mir angewöhnt, als Pfad den Paketnamen zu verwenden. Nehmen kann man alles, was einem gefällt. Streng genommen ist auch gar keiner nötig, aber so sinkt vielleicht die Gefahr, dass man Probleme mit bestehenden Keys mit gleichem Namen bekommt.

Jeder Key muss mit einem Handler definiert werden. Der einfachste ist .code, mit dem der Wert, den der Key bekommt, als #1 weiterverarbeitet werden kann.

Im Befehl am Schluss werden die Keys schließlich gesetzt. Dabei ist \pgfqkeys{/<Pfad>}{<Keys>} nur eine andere Methode für \pgfkeys{<Pfad>/.cd, <Keys>}. Gesetzt habe ich sie in einer Gruppe, damit sie beim nächsten Aufruf des Befehls wieder die Voreinstellung haben, falls sie nicht verwendet werden.

Permanenter link

beantwortet 12 Aug '14, 20:38

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 12 Aug '14, 20:53

Für pgfkeys gibt es auch anrede/.store in = \name@anrede. Damit spart man sich das \renewcommand.

(12 Aug '14, 20:57) Henri

@Henri :) kannte ich noch nicht. (Ich nutze pgfkeys sehr viel seltener als l3keys... – vielleicht hätten wir umgekehrt antworten sollen :) )

(12 Aug '14, 21:00) cgnieder

Ich hätte allerdings trotzdem .code verwendet: ich wollte absichtlich nur den meiner Meinung nach grundlegendsten Handler zeigen.

(12 Aug '14, 21:01) cgnieder

@Clemens Ich finde es so wie es ist wunderbar :) So haben wir beide was gelernt.

(12 Aug '14, 21:04) Henri
1

@cfeuersaenger hat hier noch einen weiteren Vorschlag mit pgfkeys gemacht

(15 Aug '14, 23:11) esdd

Danke @esdd. Irgendwie scheint sich meine Antwort auf die urspruengliche Frage mit der Entscheidung, eine separate Frage zu keyval zu stellen, ueberschnitten zu haben :-( Vielleicht kopiere ich die hierhin; da findet man sie besser.

(16 Aug '14, 10:35) cfeuersaenger
Ergebnis 5 von 6 show 1 more comments

Ein Ansatz mit l3keys.

anrede hat den Standardwert Herr und es gibt einen Fehler wenn man nachname oder vorname weglässt.

Open in writeLaTeX
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_feynman_anrede_tl
\tl_new:N \l_feynman_vorname_tl
\tl_new:N \l_feynman_nachname_tl

\keys_define:nn { feynman }
{
  anrede   .tl_set:N  = \l_feynman_anrede_tl,
  anrede   .initial:n = {Herr},
  vorname  .tl_set:N  = \l_feynman_vorname_tl,
  nachname .tl_set:N  = \l_feynman_nachname_tl,
}

\msg_new:nnnn { feynman } { feld-fehlt } { #1 ~ fehlt } { Das ~ Feld ~ #1 ~ muss ~ einen ~ Wert ~ haben }

\cs_new_protected:Npn \feynman_name:n #1 {
  \group_begin:
  \keys_set:nn { feynman } { #1 }
  \tl_if_empty:NT \l_feynman_vorname_tl  {
    \msg_error:nnn { feynman } { feld-fehlt } { vorname  }
  }
  \tl_if_empty:NT \l_feynman_nachname_tl {
    \msg_error:nnn { feynman } { feld-fehlt } { nachname }
  }
  \textbf{\l_feynman_anrede_tl}~
  \textsc{\l_feynman_vorname_tl}~
  \textit{\l_feynman_nachname_tl}
  \group_end:
}

\NewDocumentCommand\name{ m }{
  \feynman_name:n { #1 }
}
\ExplSyntaxOff
\begin{document}
\name{nachname=Mustermann,vorname=Max}

\name{anrede=Herr,vorname=John,nachname=Doe}
\end{document}
Permanenter link

beantwortet 12 Aug '14, 20:32

Henri's gravatar image

Henri
15.7k133943
Akzeptiert-Rate: 46%

bearbeitet 12 Aug '14, 21:21

Vielleicht kannst Du beschreiben, wo man Nachlesen kann, was Du da in dieser seltsamen Schreibweise machst ;) Am besten noch: gleich selber beschreiben

(12 Aug '14, 20:41) cgnieder

@Clemens und @Henri Danke schonmal für die Antworten, mit denen ich mich jetzt intensiv auseinandersetzen muss. Meine Programmierkenntnisse sind leider etwas beschränkt. Ich lese gerade noch in der Dokumentation zum Paket xkeyval. Vielleicht geht es ja auch damit.

(12 Aug '14, 21:03) feynman
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
×5
×3

gestellte Frage: 12 Aug '14, 20:15

Frage wurde gesehen: 13,661 Mal

zuletzt geändert: 20 Aug '14, 12:14