
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
のパラメータ内に、nameuse
、edef
、let
などを追加すると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{..}