\expandafter と同様に \expandbefore を実装するにはどうすればよいでしょうか?

\expandafter と同様に \expandbefore を実装するにはどうすればよいでしょうか?

csname新しいコマンドを定義しようとしていますが、とを使用して新しい制御文字列を「オンザフライ」で指定していますendcsname(これは依存性注入パターンを実装することを目的としています。) **あるいは、これを実行する方法はありますかexpl3?

通常、私は ... を使用してきましたが、このユースケースでは、次のようにWITHINの最初のパラメータ\expandafter\newcommandを定義したいと思います。csname\newcommand

\newcommand{\expandbefore\csname \GetCommandName \endcsname}[1]{\small I did it!!!}
\newcommand\expandbefore\csname \GetCommandName \endcsname{\small I did it again!!!}

括弧内のすべてを事前に展開しておきたいのです\newcommandが、\expandafterしかし、以前に頼ることなく\newcommand

問題:

  • 別のプロセス入力バッファ ハック (Lua を使用) に頼ることなく、LaTeX でこれを行う通常の方法があるかどうかが気になります。

  • expandafterのパラメータ内に、nameuseedefletなどを追加するとcsname\newcommandそれらのコマンドを再定義するときにエラーが発生します。( または{}クロージャbegingroup内であっても)

  • それがどのように機能するかを理解しようとすると\meaning \expandafter失敗します (予想通り、そして面白いことに)。

答え1

私は(若干の修正を加えて)答え質問に対してスペースが重要になる制御シーケンスを定義しますそれはあなたの質問にも当てはまるようです:


-記法を適用することで#{、最後の引数が開き中括弧で区切られるマクロを定義できます。引数をまとめるときに削除される他の引数区切り文字とは異なり、TeX は区切りとなる開き中括弧をそのまま残します。 (実際には、このメカニズムは開き中括弧文字トークンに限定されません。定義時にカテゴリ コードが 1 である任意のトークンを使用できます。の後でも
かまいません  。) 区切られた引数は空にすることができます。#\WeIrd\let\WeIrd={

したがって、制御シーケンス トークンを、その制御シーケンス トークンの定義と呼び出しの両方で問題の制御シーケンス トークンの名前を形成する文字トークンのセットに展開されるトークンのセットから取得するには、(- 表記を適用して#{)\name括弧で区切られた引数とそれに続く区切りのない引数 (括弧内にネストされている) を処理する単一の制御シーケンスを作成できます。TeX で引数を取得した後、TeX で引数を回転させて、\csname..\endcsname括弧内に指定された引数に適用することができます。問題の制御シーケンス トークンの名前には、スペース トークンも含めることができます。

\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}→ 拡張ステップ 1:
\UD@innername{foo}{bar}→ 拡張ステップ 2:
\expandafter\UD@exchange\expandafter{\csname bar\endcsname}{foo}→ 拡張ステップ 3:
\UD@exchange{\bar}{foo}→ 拡張ステップ 4:
foo\bar  .

拡張コンテキストでは、\expandafter結果を取得するために 4 つの -chain が必要になります。

\romannumeralは正でない数に遭遇したときにトークンを生成しないので、-チェーン\romannumeralの量を減らすために少しの-展開を追加することができます\expandafter

どちらかを実行します。この方法では、 -tokenにヒットする -chain が\romannumeral\name0 foo{bar}1 つだけ必要になります。\expandafter\romannumeral

または、\romannumeral定義内に -展開を「ハードコード」します。この方法では 2 つの\expandafter-チェーンが必要になります。最初のチェーンは、 のトップレベル展開を取得するためのものです\name。2 番目のチェーンは、 -展開を誘導するためのものです\romannumeral

\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{foo}\foo  .    (←制御シーケンスを定義せずに、 を使って呼び出して使用する方法です\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  .

名前にスペースが含まれるマクロを定義/呼び出す場合にも、次のようなマクロを使用できます。

\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␣  .

問題の制御シーケンス トークンの名前を収集しながら、\name拡張可能なトークンの拡張をトリガーします。

\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!!!}

呼び出しをネストすることもできます\name:

例1:

   \name\name\expandafter{f o o }{b a r }

最初のものを処理すると\name次のようになります
   \name\expandafter\f␣o␣o␣{b a r }  。

2 番目を処理すると次の\nameようになります
   \expandafter\f␣o␣o␣\b␣a␣r␣  。

(同様に:\name\name\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣。)

例2:

   \name\name\name\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

最初のものを処理すると\name次のようになります
   \name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  。

2 番目を処理すると次の\nameようになります
   \name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  。

3 番目を処理すると次の\nameようになります
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  。

例3:

\romannumeral拡張コンテキストでは、処理を継続するために -expansion を使用できます。

   \romannumeral\name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

\romannumeralある数字が見つかるまで拡張を続けます。最終的に数字が見つかります0が、非正の数字の場合は\romannumeralトークンは返されません。
   %\romannumneral-expansion in progress
   \name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

最初のものを処理すると\name次のようになります
   %\romannumneral-expansion in progress
   \name\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  。

2 番目を処理すると次の\nameようになります
   %\romannumneral-expansion in progress
   \name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  。

3 番目を処理すると次の\nameようになります
   %\romannumneral-expansion in progress
   0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  。

ここで、\romannumeral数値 が検索されます0。したがって、\romannumeral-expansion は中止され、\romannumeralトークンは配信されません:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  。

\name内部的には適用される\csnameが、

  • \csname拡張可能なトークンの拡張は、一致するものを検索している間に\endcsname、問題の制御シーケンス トークンの名前を形成する文字トークンを収集しながら行われます。

  • \csnameを副作用として適用すると\relax、 を適用する前に問題の制御シーケンスが未定義であった場合、問題の制御シーケンスに -プリミティブの意味が割り当てられます。の適用時に -パラメータが正の値であった\csnameとしても、その割り当ては現在のスコープに制限されます。 \globaldefs\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}

ここに画像の説明を入力してください

答え2

LaTeX には、csname トークンではなくコマンド名を取得するコマンド形式がすでにあります。

\@namedef{\GetCommandName}{\small I did it!!!}

あなたが望むことをするべきですこれは単に\expandafter\def\csname\GetCommandName\endcsname{..}

関連情報