Wie implementiert man \expandbefore ähnlich wie \expandafter?

Wie implementiert man \expandbefore ähnlich wie \expandafter?

Ich versuche, einen neuen Befehl zu definieren, aber die neue Steuerzeichenfolge „on the fly“ mit csnameund 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 csnameWITHIN \newcommandfolgendermaß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 \expandaftervorher 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 \newcommandParameters führt lediglich zu einem Fehler bei der Neudefinition dieser Befehle. (Auch in {}oder begingroupAbschlüssen.

  • Der Versuch \meaning \expandafterherauszufinden, 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 #\WeIrdnach 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..\endcsnameauf 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 \romannumeralbeim 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, \expandafterdie das -Token trifft .\romannumeral

Oder lassen Sie die \romannumeral-Erweiterung in der Definition „fest codieren“. Auf diese Weise \expandafterwerden zwei -Ketten benötigt. Die erste zum Erhalten der Topl-Level-Erweiterung von \name. Die zweite zum Induzieren \romannumeralder -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 \namewird 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 \nameErgebnisse:
   \name\expandafter\f␣o␣o␣{b a r }  .

Die Verarbeitung des zweiten \nameergibt:
   \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 \nameErgebnisse:
   \name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Die Verarbeitung des zweiten \nameergibt:
   \name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Die Verarbeitung des dritten \nameergibt:
   \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 }

\romannumeralwird so lange erweitert, bis eine Zahl gefunden wurde. Am Ende wird die Zahl gefunden, 0während bei nicht positiven Zahlen \romannumeralkein 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 \nameErgebnisse:
   %\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 \nameergibt:
   %\romannumneral-expansion in progress
   \name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Die Verarbeitung des dritten \nameergibt:
   %\romannumneral-expansion in progress
   0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Findet jetzt \romannumeraldie Nummer 0. Daher \romannumeralwird die -Erweiterung abgebrochen und \romannumeralliefert kein Token:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Beachten Sie, dass \nameintern gilt \csname, während

  • Die Erweiterung erweiterbarer Token erfolgt, während \csnamebei der Suche nach dem passenden Token \endcsnamedie Zeichen-Token gesammelt werden, die den Namen des betreffenden Steuersequenz-Tokens bilden.

  • Das Anwenden \csnameals 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}

Bildbeschreibung hier eingeben

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{..}

verwandte Informationen