
Ich versuche, einen neuen Befehl zu definieren, aber die neue Steuerzeichenfolge „on the fly“ mit csname
und anzugeben endcsname
.(Dies dient der Implementierung eines Abhängigkeitsinjektionsmusters.) **Gibt es alternativ eine Möglichkeit, dies mit zu tun expl3
?
Normalerweise verwende ich \expandafter\newcommand
..., aber in diesem Anwendungsfall möchte ich den ersten Parameter von csname
WITHIN \newcommand
folgendermaßen definieren:
\newcommand{\expandbefore\csname \GetCommandName \endcsname}[1]{\small I did it!!!}
\newcommand\expandbefore\csname \GetCommandName \endcsname{\small I did it again!!!}
Ich möchte, dass alles innerhalb der Klammern VORHER erweitert wird \newcommand
-aber ohne sich auf \expandafter
vorher zu verlassen\newcommand
.
Probleme:
Ich bin gespannt, ob es eine normale Möglichkeit gibt, dies in LaTeX zu tun, ohne auf einen anderen Hack für den Prozess-Eingabepuffer (mit Lua) angewiesen zu sein.
Das Hinzufügen von
expandafter
,nameuse
,edef
,let
,csname
, usw. innerhalb des\newcommand
Parameters führt lediglich zu einem Fehler bei der Neudefinition dieser Befehle. (Auch in{}
oderbegingroup
Abschlüssen.Der Versuch
\meaning
\expandafter
herauszufinden, wie es funktioniert, schlägt fehl (vorhersehbar und auch lustig).
Antwort1
Ich zitiere (mit leichten Modifikationen) meineAntwortzur FrageDefinieren Sie eine Steuersequenz, danach kommt ein Leerzeichenda es auch auf Ihre Frage zuzutreffen scheint:
Durch Anwenden der #{
-Notation können Sie Makros definieren, deren letztes Argument durch eine öffnende Klammer abgegrenzt wird. Anders als bei anderen Argumentbegrenzern, die beim Sammeln der Argumente entfernt werden, lässt TeX eine begrenzende öffnende Klammer bestehen.
(Tatsächlich ist der Mechanismus nicht auf Zeichentoken mit öffnenden Klammern beschränkt. Sie können jedes Token verwenden, dessen Kategoriecode zum Zeitpunkt der Definition 1 ist. Könnte auch #\WeIrd
nach stehen \let\WeIrd={
.)
Abgegrenzte Argumente können leer sein.
Um also ein Kontrollsequenztoken aus einer Menge von Token zu erhalten, die sich zu einer Menge von Zeichentoken erweitert, die den Namen des betreffenden Kontrollsequenztokens sowohl zum Definieren als auch zum Aufrufen dieses Kontrollsequenztokens bildet, können Sie (durch Anwenden der #{
-Notation) eine einzelne Kontrollsequenz erfinden \name
, die ein durch Klammern begrenztes Argument verarbeitet, dem ein nicht begrenztes Argument (das in Klammern verschachtelt ist) folgt. Nachdem TeX die Argumente abgerufen hat, können Sie sie von TeX umherwirbeln lassen und \csname..\endcsname
auf das in Klammern angegebene Argument anwenden. Der Name des betreffenden Kontrollsequenztokens kann auch Leerzeichen enthalten.
\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
\expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother
\name foo{bar}
→ Ausbaustufe 1:
\UD@innername{foo}{bar}
→ Ausbaustufe 2:
\expandafter\UD@exchange\expandafter{\csname bar\endcsname}{foo}
→ Ausbaustufe 3:
\UD@exchange{\bar}{foo}
→ Ausbaustufe 4:
foo\bar
.
In Erweiterungskontexten benötigen Sie vier \expandafter
-Ketten, um das Ergebnis zu erhalten.
Da \romannumeral
beim Auftreten einer nicht positiven Zahl kein Token erzeugt wird, können Sie eine kleine \romannumeral
-Erweiterung hinzufügen, um die Anzahl der \expandafter
-Ketten zu reduzieren.
Tun Sie dies entweder \romannumeral\name0 foo{bar}
. Auf diese Weise ist nur eine -Kette erforderlich, \expandafter
die das -Token trifft .\romannumeral
Oder lassen Sie die \romannumeral
-Erweiterung in der Definition „fest codieren“. Auf diese Weise \expandafter
werden zwei -Ketten benötigt. Die erste zum Erhalten der Topl-Level-Erweiterung von \name
. Die zweite zum Induzieren \romannumeral
der -Erweiterung.
\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
\expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother
Mit einem solchen Makro sind Sie nicht an bestimmte Definitionsbefehle gebunden:
\name{foo}
→ \foo
. (←Dies ist die Art und Weise, bei der Sie Steuersequenzen nicht definieren, sondern lediglich mittels aufrufen/verwenden \name
.)
\name\newcommand{foo}
→ \newcommand\foo
.
\name\DeclareRobustCommand{foo}
→ \DeclareRobustCommand\foo
.
\name\global\long\outer\def{foo}
→ \global\long\outer\def\foo
.
\name\expandafter{foo}\bar
→ \expandafter\foo\bar
.
\name\let{foo}=\bar
→ \let\foo=\bar
.
\name\string{foo}
→ \string\foo
.
\name\meaning{foo}
→ \meaning\foo
.
Sie können ein solches Makro auch zum Definieren/Aufrufen von Makros verwenden, deren Namen Leerzeichen enthalten:
\name{foo }
→ \foo␣
.
\name\newcommand{foo }
→ \newcommand\foo␣
.
\name\DeclareRobustCommand{foo }
→ \DeclareRobustCommand\foo␣
.
\name\global\long\outer\def{foo }
→ \global\long\outer\def\foo␣
.
\name\expandafter{foo }\bar
→ \expandafter\foo␣\bar
.
\name\let{foo }=\bar
→ \let\foo␣=\bar
.
\name\string{foo }
→ \string\foo␣
.
\name\meaning{foo }
→ \meaning\foo␣
.
Beim Erfassen des Namens des betreffenden Steuersequenztokens \name
wird die Erweiterung erweiterbarer Token ausgelöst:
\def\GetCommandName{FooBar}
\name\newcommand{\GetCommandName}[1]{\small I did it!!!}
→\newcommand\FooBar[1]{\small I did it!!!}
\def\GetCommandName{\CommandNamePartA\CommandNamePartB}
\def\CommandNamePartA{Ba}
\def\CommandNamePartB{r\InnerCommandNamePart o}
\def\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}
→\newcommand\BarFoo{\small I did it again!!!}
Sie können die Aufrufe auch verschachteln in \name
:
Beispiel 1:
\name\name\expandafter{f o o }{b a r }
Die Verarbeitung der ersten \name
Ergebnisse:
\name\expandafter\f␣o␣o␣{b a r }
.
Die Verarbeitung des zweiten \name
ergibt:
\expandafter\f␣o␣o␣\b␣a␣r␣
.
(Analog: \name\name\let{f o o }={b a r }
→ \let\f␣o␣o␣=\b␣a␣r␣
.)
Beispiel 2:
\name\name\name\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }
Die Verarbeitung der ersten \name
Ergebnisse:
\name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }
.
Die Verarbeitung des zweiten \name
ergibt:
\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }
.
Die Verarbeitung des dritten \name
ergibt:
\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣
.
Beispiel 3:
In Erweiterungskontexten können Sie \romannumeral
-expansion verwenden, um die Dinge am Laufen zu halten.
\romannumeral\name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }
\romannumeral
wird so lange erweitert, bis eine Zahl gefunden wurde. Am Ende wird die Zahl gefunden, 0
während bei nicht positiven Zahlen \romannumeral
kein Token zurückgegeben wird:
%\romannumneral-expansion in progress
\name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }
Die Verarbeitung der ersten \name
Ergebnisse:
%\romannumneral-expansion in progress
\name\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }
.
Die Verarbeitung des zweiten \name
ergibt:
%\romannumneral-expansion in progress
\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }
.
Die Verarbeitung des dritten \name
ergibt:
%\romannumneral-expansion in progress
0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣
.
Findet jetzt \romannumeral
die Nummer 0
. Daher \romannumeral
wird die -Erweiterung abgebrochen und \romannumeral
liefert kein Token:
\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣
.
Beachten Sie, dass \name
intern gilt \csname
, während
Die Erweiterung erweiterbarer Token erfolgt, während
\csname
bei der Suche nach dem passenden Token\endcsname
die Zeichen-Token gesammelt werden, die den Namen des betreffenden Steuersequenz-Tokens bilden.Das Anwenden
\csname
als Nebeneffekt führt dazu, dass der betreffenden Steuersequenz die Bedeutung des\relax
-Primitivs zugewiesen wird, falls die betreffende Steuersequenz vor dem Anwenden nicht definiert war\csname
. Diese Zuweisung wird auf den aktuellen Bereich beschränkt, auch wenn der\globaldefs
-Parameter zum Zeitpunkt des Anwendens einen positiven Wert hatte\csname
.
%%\errorcontextlines=1000
\documentclass[a4paper]{article}
\usepackage{textcomp}%
\parindent=0cm
\parskip=\medskipamount
\makeatletter
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
\expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother
\name\newcommand{foo}[2]{%
Control sequence whose name does not contain any space.\\
Argument 1: \textit{\textlangle#1\textrangle}\\
Argument 2: \textit{\textlangle#2\textrangle}
}%
\name\newcommand{foo }[2]{%
Control sequence whose name has a trailing space.\\
Argument 1: \textit{\textlangle#1\textrangle}\\
Argument 2: \textit{\textlangle#2\textrangle}
}%
\name\newcommand{ f o o }[2]{%
Control sequence whose name is interspersed with spaces.\\
Argument 1: \textit{\textlangle#1\textrangle}\\
Argument 2: \textit{\textlangle#2\textrangle}
}%
\newcommand*\GetCommandName{\CommandNamePartA\CommandNamePartB}
\newcommand*\CommandNamePartA{Ba}
\newcommand*\CommandNamePartB{r\InnerCommandNamePart o}
\newcommand*\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}
\begin{document}
\name{foo}{Arg 1}{Arg 2}
\name{foo }{Arg 1}{Arg 2}
\name{ f o o }{Arg 1}{Arg 2}
Nesting \texttt{\string\name}:
\name\expandafter\newcommand\expandafter*\expandafter{C o N f u SiO n}\expandafter{%
\romannumeral\name\name\name0 %
\expandafter\expandafter\expandafter{F O O}\expandafter{B A R}{C R A Z Y}%
}%
\texttt{\name\string{C o N f u SiO n} is \name\meaning{C o N f u SiO n}}%
\\
Playing around with expandable tokens:
\texttt{\name\string{\GetCommandName}:}
\texttt{\name\meaning{\GetCommandName}}
\name{\GetCommandName}%
Playing around with grouping:
%Be aware that \texttt itself opens up a new scope for typesetting its argument.
%\globaldefs=1\relax
\texttt{%
\begingroup\name\string{w e i r d } is \name\endgroup\meaning{w e i r d }%
}%
\texttt{%
\name\string{w e i r d } is \name\meaning{w e i r d }%
}%
\end{document}
Antwort2
LaTeX verfügt bereits über eine Befehlsform, die den Namen eines Befehls anstelle des csname-Tokens verwendet:
\@namedef{\GetCommandName}{\small I did it!!!}
sollte tun, was Sie wollen, das ist einfach\expandafter\def\csname\GetCommandName\endcsname{..}