Ich habe folgendes Paket
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypkg}
\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}
\newcommand*\showDF[1]{\csname @#1\endcsname}
\endinput
Es bietet dem Benutzer den Befehl \Mycmd{}
zum Erneuern \@mycmd
und \showDF{mycmd}
Anzeigen des Inhalts:
\documentclass[a4paper,titlepage,11pt,twoside,openright]{report}
\usepackage{mypkg}
\begin{document}
\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}
\end{document}
Ich möchte die ersten beiden Befehle mit einem Makro definieren, um mehrere Befehlspaare zu generieren.
\@newDF{mycmd}{Mycmd}
Ich habe es versucht mit
\newcommand*\@newDF[2]{
\providecommand*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
\newcommand*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}
aber es läuft nicht.
\newcommand*\newDF[2]{
\expandafter\providecommand\expandafter*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
\expandafter\newcommand\expandafter*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}
kompiliert, aber ich weiß wirklich nicht, warum ich diese \expandafter
dort eingefügt habe. Außerdem wird es bei der Ausführung \MakeUppercase
ignoriert und hat keine Auswirkung. Das Ersetzen durch entweder oder keines funktioniert. Was übersehe ich?\showDF{mycmd}
\Mycmd{Hi}
\csname @#1\endcsname
@nameuse{@#1}
\csuse{@#1}
Antwort1
Kurz gesagt, der Grund, warum Ihre Verwendung von \expandafter
fehlschlägt, ist, dass Sie nicht genug davon haben. Weitere Einzelheiten finden Sie in den ausführlichen Erklärungen hierzu an anderer Stelle auf dieser Site, beispielsweisewarum-brauchen-wir-elf-expandafters-um-vier-tokens-in-der-richtigen-reihenfolge-zu-expandieren.
Das Problem, das Sie damit haben, \MakeUppercase
ist, dass es nicht erweiterbar ist, was bedeutet, dass Sie es nicht direkt innerhalb einer \csname...\endcsname
Definition verwenden können. Dies wird in den Antworten auf den Beitrag ausführlich erklärt
Erstellen Sie ein Makro-Token in Großbuchstaben mit CSNAME.
Werner hat eine Lösung angegeben, mit der er das Problem mit den Großbuchstaben vermeidet, indem er sowohl den Namen in Großbuchstaben als auch in Kleinbuchstaben an den Makro-Ersteller weitergibt. Hier ist eine weitere Lösung, die den Makro-Namen automatisch in Großbuchstaben umwandelt.
Anstatt \providescommand
zu prüfen, ob das \@my<command>
bereits definiert wurde, überprüfe ich dies direkt mit, \ifcsdef
da die Verwendung \providescommand
einige s erfordern würde \expandafter
, die ich lieber vermeiden würde. Schließlich definiert der folgende Code als Bonus auch eine „Factory-Funktion“ \@DefineMyCommands
zum Erstellen einer Familie solcher Befehle aus einer durch Kommas getrennten Liste.
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand\@DefineMyCommand[1]{\@ReallyDefineMyCommand#1\relax}
\def\@ReallyDefineMyCommand#1#2\relax{%
% Define command <#1#2> to set @my#1#2={arg of <#1#2>}
% Here #1 is the first character of the comamnd and #2 is the rest.
% We have isolated #1 so that we can uppercase it on the next line
\uppercase{\expandafter\gdef\csname #1}#2\endcsname##1{\@namedef{@my#1#2}{##1}}
% if \@my#1#2 is not already defined then define it
\ifcsdef{@my#1#2}{\relax}{\@namedef{@my#1#2}{No \MakeUppercase{#1#2} defined!}}
}
\newcommand{\@DefineMyCommands}{\forcsvlist{\@DefineMyCommand}}% factory function
\@DefineMyCommands{mycmd, test, fred, julie}% define a bunch of macros
\makeatother
\newcommand*\showDF[1]{\csname @my#1\endcsname}
\begin{document}
\showDF{mycmd}
\Mycmd{A command!}
\showDF{mycmd}
\showDF{test}
\Test{A test!}
\showDF{test}
\end{document}
Hier ist die „erwartete“ Ausgabe:
BearbeitenEigentlich ist es ein bisschen albern, einen Factory-Befehl zu definieren, wenn er nur einmal verwendet werden soll. Sofern es nicht eine große Anzahl dieser Makros gibt, wäre es klüger, Folgendes zu schreiben:
\forcsvlist{\@DefineMyCommand}{mycmd, test, fred, julie}
da dadurch der Befehl \@DefineMyCommand
auf die Elemente in der Liste angewendet wird, ohne ein unnötiges Makro zu erstellen.
Antwort2
So können Sie das tun:
\documentclass{article}
\makeatletter
%\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
%\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}
\newcommand{\@newDF}[2]{%
\@namedef{@#1}{No \MakeUppercase{#2} defined}%
%\expandafter\newcommand\csname @#1\endcsname{No \MakeUppercase{#2} defined}% Alternative to above
\expandafter\newcommand\csname #2\endcsname[1]{%
\expandafter\renewcommand\csname @#1\endcsname{##1}}
}
\@newDF{mycmd}{Mycmd}
\newcommand*\showDF[1]{\csname @#1\endcsname}
\makeatother
\begin{document}
\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}
\end{document}
Die Ausgabe lautet:
Kein MYCMD-definierter
Test
DerDefinitionen werden mit einem\show
:
> \@mycmd=macro:
->No \MakeUppercase {Mycmd} defined.
> \Mycmd=\long macro:
#1->\expandafter \renewcommand \csname @mycmd\endcsname {#1}.