Wie verwende ich \csname, \expandafter, \csuse, \@namedef ...?

Wie verwende ich \csname, \expandafter, \csuse, \@namedef ...?

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 \@mycmdund \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 \expandafterdort eingefügt habe. Außerdem wird es bei der Ausführung \MakeUppercaseignoriert 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 \expandafterfehlschlä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, \MakeUppercaseist, dass es nicht erweiterbar ist, was bedeutet, dass Sie es nicht direkt innerhalb einer \csname...\endcsnameDefinition 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 \providescommandzu prüfen, ob das \@my<command>bereits definiert wurde, überprüfe ich dies direkt mit, \ifcsdefda die Verwendung \providescommandeinige s erfordern würde \expandafter, die ich lieber vermeiden würde. Schließlich definiert der folgende Code als Bonus auch eine „Factory-Funktion“ \@DefineMyCommandszum 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:

Bildbeschreibung hier eingeben

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 \@DefineMyCommandauf 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}.

verwandte Informationen