Optionale Parameter in eigenen Befehlen

Antwort erstellen


Diese Frage dient dazu, das automatisierte Versenden von Formularen durch Spam-Bots zu verhindern.
Smilies
:D :) :( :o :shock: :? 8) :lol: :-x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen:

Markdown is OFF

BBCode ist eingeschaltet
[img] ist eingeschaltet
[flash] ist ausgeschaltet
[url] ist eingeschaltet
Smilies sind eingeschaltet

Die letzten Beiträge des Themas

Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden.

   

Wenn du eine Datei oder mehrere Dateien anhängen möchtest, gib die Details unten ein.

Ansicht erweitern Die letzten Beiträge des Themas: Optionale Parameter in eigenen Befehlen

von phi » Mi 20. Jan 2010, 17:32

Hier noch die äquivalente Version mit xparse:

Code: Alles auswählen

\usepackage{etex}
\usepackage{xparse}
\ExplSyntaxOn
% mit \ExplSyntaxOn können fast beliebig Leerzeichen und Zeilenumbrüche eingefügt werden
\NewDocumentCommand \Quelle { o m } {
  \IfValueTF { #1 } {
    \cite [ S. \nobreakspace #1 ] { #2 } % ~ wird hier als normales Leerzeichen verwendet, für ein
                                         % Leerzeichen ohne Umbruch muss deshalb \nobreakspace eingesetzt werden
  } {
    \cite { #2 }
  }
}
\ExplSyntaxOff
Auch andere Varianten sind denkbar, etwa:

Code: Alles auswählen

\usepackage{etoolbox}
\newrobustcmd*{\Quelle}[2][]{%
  \ifstrempty{#1}{%
    \cite{#2}%
  }{%
    \cite[S.~#1]{#2}%
  }%
}
Diese Variante unterscheidet sich allerdings von den anderen durch ihre Behandlung eines leeren optionalen Arguments.

von phi » Mi 20. Jan 2010, 17:16

Hallo,

ich habe den Beitrag leider erst jetzt entdeckt, antworte aber trotzdem, vielleicht nützt es noch was.
IrenaSekuta hat geschrieben:Habe deinen Code in eine für mich etwas lesbarere Fassung gebracht:

Code: Alles auswählen

\makeatletter
\newcommand*{\Quelle}{%
  \@ifnextchar{[}{\Quell@}{\Qu@lle}
}
\def\Qu@lle#1{\cite{#1}\xspace}
\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\makeatother
Vorsicht vor solchen "Verbesserungen", wenn du nicht genau verstehst, was vor sich geht! In diesem Fall funktioniert das zwar, aber auch nur aufgrund eines Implementierungsdetails von \@ifnextchar. Ich würde deshalb raten, weiterhin meine ursprüngliche Version zu benutzen.
Durch probieren habe ich herausgefunden, dass folgende Zeilen Code quasi dasselbe tun:

Code: Alles auswählen

\def\Qu@lle#1{\cite{#1}\xspace}
und
\newcommand{\Qu@lle}[1]{\cite{#1}\xspace}
Ja, diese Definitionen sind nahezu völlig äquivalent. Die einzigen Unterschiede sind, dass der zweite Code auch Absatzenden als Argument zulässt (was in der Regel nicht erwünscht ist und mit \newcommand* verhindert werden kann), und dass ein eventuell schon vorhandener Befehl nicht überschrieben wird.
Aber komischerweise funktioniert es bei folgender Codeänderung nicht:

Code: Alles auswählen

\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\newcommand{\Quell@}[2]{\cite[S.~#1]{#2}\xspace}
Warum funktioniert der zweite von mir erstellte Code nicht?
Weil die Syntax anders ist. \Quell@ erwartet genau eine öffnende eckige Klammer, einen Parameter, eine schließende eckige Klammer und noch einen Parameter. Dies lässt sich mit \newcommand nicht darstellen.
Und noch eine allgemeine Frage:

Hat deine Schreibweise gegenüber meiner irgendwelche Vor-/Nachteile oder ist dein Code "besser", weil er eventuell andere Probleme vermeidet, die ich momentan aufgrund meines rudimentären Latex-Programmier-Wissens nicht erkennen?
Generell sollte man auf der obersten möglichen Ebene arbeiten, d.h. \newcommand benutzen. Da dies hier nicht möglich ist, muss man auf TeX-Primitven zurückgreifen. (Das experimentelle xparse-Paket bietet weitere Möglichkeiten, mit denen sich auch Befehle wie der hier besprochene sehr komfortabel definieren lassen.)
Generell sollte man nicht erwarten, bei internen Befehlen wie \@ifnextchar (erkennbar am @ im Befehlsnamen) Klammer nach Belieben weglassen oder hinzufügen zu können.
Essentiell ist die Beachtung von Leerzeichen: TeX fügt bei fast jedem Zeilenende (außer dieser beendet einen Absatz oder ein Steuernamenstoken ist das letzte Token auf der Zeile) ein Leerzeichen ein, egal ob im Text oder in Befehlsdefinitionen. Deswegen sollten die problematischen Zeilenumbrüche in Befehlsdefinitionen mit einem Kommentarzeichen maskiert werden (so wie ich das bei meinen Definitionen auch gemacht habe).

von IrenaSekuta » So 27. Dez 2009, 10:46

Hallo phi,

recht herzlichen Dank für deine tolle Erklärung. Habe deinen Code in eine für mich etwas lesbarere Fassung gebracht:

Code: Alles auswählen

\makeatletter
\newcommand*{\Quelle}{%
  \@ifnextchar{[}{\Quell@}{\Qu@lle}
}
\def\Qu@lle#1{\cite{#1}\xspace}
\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\makeatother
Eventuell kannst Du mir noch helfen, den Code vollständig zu verstehen.

Durch probieren habe ich herausgefunden, dass folgende Zeilen Code quasi dasselbe tun:

Code: Alles auswählen

\def\Qu@lle#1{\cite{#1}\xspace}
und
\newcommand{\Qu@lle}[1]{\cite{#1}\xspace}
Aber komischerweise funktioniert es bei folgender Codeänderung nicht:

Code: Alles auswählen

\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\newcommand{\Quell@}[2]{\cite[S.~#1]{#2}\xspace}
Warum funktioniert der zweite von mir erstellte Code nicht?

Und noch eine allgemeine Frage:

Hat deine Schreibweise gegenüber meiner irgendwelche Vor-/Nachteile oder ist dein Code "besser", weil er eventuell andere Probleme vermeidet, die ich momentan aufgrund meines rudimentären Latex-Programmier-Wissens nicht erkennen?

Liebe Grüße,

Irena

von phi » Sa 26. Dez 2009, 18:43

IrenaSekuta hat geschrieben:Hallo phi,

herzlichen Dank für deinen Code, aber leider funktioniert der Code nur teilweise..

Anbei das Minimalbeispiel:

Code: Alles auswählen

\documentclass[ngerman]{scrbook}
\usepackage[T1]{fontenc}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage{cite}
\usepackage{xspace}

\makeatletter
\newcommand*{\Quelle}{%
  \@ifnextchar[\Quell@\Qu@lle
}
\def\Qu@lle#1{\cite{#1}\xspace}
\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\makeatother


\begin{document}


Hier wird nun auf \Quelle{3}{Lit1} referenziert und hier nun auf \Quelle{Lit2}.

\begin{thebibliography}{Literatur}
\bibitem[Literaturstelle 1]{Lit1} Erste Literaturstelle
\bibitem[Literaturstelle 2]{Lit2}zweiteLiteraturstelle
\end{thebibliography}
\end{document} 
Hallo,
die Syntax des \Quelle-Befehls entspricht den normalen Befehlen mit optionalem Argument, d.h. das optionale Argument muss in eckige Klammern:
\Quelle[3]{Lit1}
Eine Syntax mit geschweiften Klammern wäre möglich, aber schwieriger zu realisieren und inkonsistent mit der Syntax der übrigen LaTeX-Befehle.

Ungeachtet dessen verstehe ich absolut nicht, was der Code machen soll.

Eventuell können wir den Code gemeinsam auseinander nehmen, sodass ich auch dabei lernen kann, wie man in Tex programmiert:

Code: Alles auswählen

\newcommand*{\Quelle}{
  \@ifnextchar[\Quell@\Qu@lle}
Handelt es sich hier um einen Tippfehler? Du eröffnest nach @ifnextchar mit einer "[" schließt diese Klammer jedoch nie.
Nein. Der Befehl \@ifnextchar aus dem LaTeX-Kernel erwartet drei Argumente:
1. ein einzelnes Token (z.B. ein Zeichen), auf das getestet werden soll,
2. der Code, der ausgeführt werden soll, wenn das nächste Zeichen dem ersten Argument entspricht,
3. der Code, der andernfalls ausgeführt werden soll.
In der Regel ist das erste Argument ein einzelnes Zeichen (hier "[") und die zwei anderen Argumente sind Makros, die die restlichen Argumente aufsammeln.
In diesem Fall wird das Makro \Qu@lle aufgerufen, wenn keine eckige Klammer folgt, ansonsten das Makro \Quell@. Diese sammeln die Argumente ihrer Syntax entsprechend auf (siehe beispielsweise das Kapitel über Makros in TeX by Topic) und expandieren zu den gewünschten Ergebnissen. Die Technik, die \@ifnextchar verwendet, wird in Abschnitt 11.9.3 von TeX by Topic beschrieben.

von IrenaSekuta » Sa 26. Dez 2009, 14:04

Hallo phi,

herzlichen Dank für deinen Code, aber leider funktioniert der Code nur teilweise..

Anbei das Minimalbeispiel:

Code: Alles auswählen

\documentclass[ngerman]{scrbook}
\usepackage[T1]{fontenc}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage{cite}
\usepackage{xspace}

\makeatletter
\newcommand*{\Quelle}{%
  \@ifnextchar[\Quell@\Qu@lle
}
\def\Qu@lle#1{\cite{#1}\xspace}
\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\makeatother


\begin{document}


Hier wird nun auf \Quelle{3}{Lit1} referenziert und hier nun auf \Quelle{Lit2}.

\begin{thebibliography}{Literatur}
\bibitem[Literaturstelle 1]{Lit1} Erste Literaturstelle
\bibitem[Literaturstelle 2]{Lit2}zweiteLiteraturstelle
\end{thebibliography}
\end{document} 
Ungeachtet dessen verstehe ich absolut nicht, was der Code machen soll.

Eventuell können wir den Code gemeinsam auseinander nehmen, sodass ich auch dabei lernen kann, wie man in Tex programmiert:

Code: Alles auswählen

\newcommand*{\Quelle}{
  \@ifnextchar[\Quell@\Qu@lle}
Handelt es sich hier um einen Tippfehler? Du eröffnest nach @ifnextchar mit einer "[" schließt diese Klammer jedoch nie.

Gruß,

Irena[/quote]

von phi » Mi 23. Dez 2009, 22:26

etwa so:

Code: Alles auswählen

\makeatletter
\newcommand*{\Quelle}{%
  \@ifnextchar[\Quell@\Qu@lle
}
\def\Qu@lle#1{\cite{#1}\xspace}
\def\Quell@[#1]#2{\cite[S.~#1]{#2}\xspace}
\makeatother

von IrenaSekuta » Mi 23. Dez 2009, 19:13

Hallo Benedikt,

danke für den Link, jedoch gestalltet sich das Problem bei mir etwas schwieriger.

Ich will ja das die komplette Zeichenkette

Code: Alles auswählen

[S.~#1]
in

Code: Alles auswählen

\newcommand*{\Quelle}[2]{\xspace{}\cite[S.~#1]{#2}\xspace{}}
weggelassen wird, wenn #1 nicht übergeben wird.

Geht denn so etwas nicht mit einer Art If-Abfrage:

Gruß,

Irena[/code]

von cliffhanger » Mi 23. Dez 2009, 16:59

Hi Irina,

das Stichwort heißt "Optionales Argument". Vielleicht hilft dir der folgende Link

http://de.wikibooks.org/wiki/LaTeX-Wört ... newcommand

(Die Forensoftare scheint von Umlauten in URLs nicht so begeistert zu sein. Also bitte kopieren und per Hand in die Adresszeile einfügen.)
ja schonmal weiter?

Gruß
Benedikt

Optionale Parameter in eigenen Befehlen

von IrenaSekuta » Mi 23. Dez 2009, 13:21

Hallo zusammen,

ich möchte mir einen eigene Befehl konstruieren, um auf das Literaturverzeichnis zuzugreifen:


Code: Alles auswählen

\documentclass[ngerman]{scrbook}
\usepackage[T1]{fontenc}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage{cite}
\usepackage{xspace}

\newcommand*{\Quelle}[2]{\xspace{}\cite[S.~#1]{#2}\xspace{}}


\begin{document}

\begin{thebibliography}{Literatur}

Hier wird nun auf \Quelle{3}{Lit1} referenziert und hier nun auf \cite{Lit2}.

\bibitem{Li1} Erste Literaturstelle
\bibitem{Li2} zweiteLiteraturstelle

\end{thebibliography}


\end{document}
In dem Satz habe ich \cite{Lit2}geschrieben, weil ich hier einfach auf die Literatur ohne irgendwelche Seitenangaben referenzieren will. Lieber wäre mit aber, wenn ich z.B. \Quelle{}{Lit2} schreiben könnte. Das bedeutet, wenn der erste Paramter übergeben wird soll der Befehl aussehen wie

Code: Alles auswählen

\newcommand*{\Quelle}[2]{\xspace{}\cite[S.~#1]{#2}\xspace{}}
Wenn der erste Parameter nicht übergeben wird, dann eben so:

Code: Alles auswählen

\newcommand*{\Quelle}[1]{\xspace{}\cite{#1}\xspace{}}
Hat jemand einen Tipp?

Gruß,

Irena

Nach oben