我想创建一个宏,该宏会在通过宏\foo
执行之前创建另一个宏,该宏的自定义名称已设置,并保存/添加一些内容,如以下伪 latex 代码所示。是否可以将其转换为一个工作示例?\foo
\defcommand{myCustomName}
LaTeX
%\defcommand needs to be defined
%addtocommand needs to be defined
\newcommand{\foo}[1]{
%If the command \???CustomString??? doesn't exist, create it and then add the content of #1 to it.
\addtocommand{???CustomString???}{#1}
}
Some text
\defcommand{customA}
\foo{A1} \foo{A2} \foo{A3} %should create a command named `customA` (instead of ???CustomString???) which I can use in the whole document.
\customA %this schould print A1 A2 A3
some text...
\defcommand{customB}
\foo{B1},\foo{B2} %now \foo should create another command named `customB`...
\customB %should print A1 A2 A3
\customA %should print B1 B2
请注意,我不想使用 的参数来\foo
执行此操作。即我不想写\foo{Ax}{\customA}
。
答案1
如果前缀始终是一个字母,那么您可以这样做:
\makeatletter
\newcommand{\defcommand}[1]{\@namedef{custom#1}{}}
\newcommand{\foo}[1]{\@foo#1\@nil}
\def\@foo#1#2\@nil{%
\expandafter\ifx\csname custom#1\endcsname\@empty
\expandafter\g@addto@macro\csname custom#1\endcsname{#1#2}%
\else
\expandafter\g@addto@macro\csname custom#1\endcsname{ #1#2}%
\fi}
\makeatother
\defcommand{A}
\foo{A1}\foo{A2}\foo{A355}
\defcommand{B}
\foo{B123} \foo{Ba} \foo{B3}
\show\customA
\show\customB
这将在终端上打印
> \customA=macro:
->A1 A2 A355.
l.19 \show\customA
?
> \customB=macro:
->B123 Ba B3.
l.20 \show\customB
当然,如果你愿意的话,这是行不通的
\defcommand{ABC}
和\foo{ABC1}
,因为不可能知道前缀是什么。
如果前缀可能由多个字母组成,我建议采用不同的语法:
\makeatletter
\newcommand{\defcommand}[1]{\@namedef{custom#1}{}}
\newcommand{\foo}[2]{%
\expandafter\ifx\csname custom#1\endcsname\@empty
\expandafter\g@addto@macro\csname custom#1\endcsname{#1#2}%
\else
\expandafter\g@addto@macro\csname custom#1\endcsname{ #1#2}%
\fi}
\makeatother
\defcommand{A}
\foo{A}{1}\foo{A}{2}\foo{A}{355}
\defcommand{ABC}
\foo{ABC}{123} \foo{ABC}{a} \foo{ABC}{3}
\show\customA
\show\customABC
这将在终端上打印
> \customA=macro:
->A1 A2 A355.
l.17 \show\customA
?
> \customABC=macro:
->ABC123 ABCa ABC3.
l.18 \show\customABC
如果目的是建立一个后续调用应该添加的宏,那么情况就不同了。
\makeatletter
\newcommand{\defcommand}[1]{%
\gdef#1{}%
\gdef\foo@current@command{#1}%
}
\newcommand{\foo}[1]{%
\expandafter\ifx\foo@current@command\@empty
\expandafter\g@addto@macro\foo@current@command{#1}%
\else
\expandafter\g@addto@macro\foo@current@command{ #1}%
\fi
}
\makeatother
\defcommand{\macroA}
\foo{x} \foo{y} \foo{z}
\defcommand{\macroB}
\foo{Here}\foo{is}\foo{a}\foo{new}\foo{one}
\show\macroA
\show\macroB
这将在终端上打印
> \macroA=macro:
->x y z.
l.21 \show\macroA
?
> \macroB=macro:
->Here is a new one.
l.22 \show\macroB
诀窍是\foo
始终根据相同的包装器命令进行定义,并添加到\defcommand
定义包装器命令的部分作为初始化的当前宏。
最后一组宏是如何工作的?让我们以慢动作来看一下。
这里是
\defcommand
:\newcommand{\defcommand}[1]{% \gdef#1{}% \gdef\foo@current@command{#1}% }
如果我们说
\defcommand{\mymacro}
效果将是初始化\mymacro
为具有空扩展。那么(全局)定义将使其\foo@current@command
扩展为\mymacro
(而不是的内容\mymacro
,至少在第一次扩展时)。以下是
\foo
\newcommand{\foo}[1]{% \expandafter\ifx\foo@current@command\@empty \expandafter\g@addto@macro\foo@current@command{#1}% \else \expandafter\g@addto@macro\foo@current@command{ #1}% \fi }
这有一些复杂,所以让我们看一个简化的版本:
\newcommand{\foo}[1]{% \expandafter\g@addto@macro\foo@current@command{#1}% }
必须知道将
\g@addto@macro
其第二个参数添加到作为第一个参数给出的(无参数)宏中。因此,假设我们已经声明\defcommand{\mymacro}
,然后我们这样做\foo{x}
:这变成\expandafter\g@addto@macro\foo@current@command{x}
现在
\expandafter
开始行动,改变\foo@current@command
其第一级扩展,\mymacro
得到\g@addto@macro\mymacro{x}
它可以完成所需的任务。
使用更复杂的定义来确保我们添加的第一个项前面没有添加空格:
\newcommand{\foo}[1]{% \expandafter\ifx\foo@current@command\@empty \expandafter\g@addto@macro\foo@current@command{#1}% \else \expandafter\g@addto@macro\foo@current@command{ #1}% \fi }
让我们假设现在
\defcommand{\bar}
刚刚给出,所以现在\foo@current@command
扩展为\bar
,其扩展为空。只要我们说\foo{abc}\foo{def}
,TeX 就会将其转换为\expandafter\ifx\foo@current@command\@empty \expandafter\g@addto@macro\foo@current@command{#1}% \else \expandafter\g@addto@macro\foo@current@command{ #1}% \fi \foo{def}
第一个
\expandafter
变化\foo@current@command
为\bar
:\ifx\bar\@empty \expandafter\g@addto@macro\foo@current@command{abc}% \else \expandafter\g@addto@macro\foo@current@command{ abc}% \fi \foo{def}
现在
\bar
有空扩展,因此遵循“真实”分支:\expandafter\g@addto@macro\foo@current@command{abc}% \foo{def}
然后再次,
\g@addto@macro\bar{abc}\foo{def}
因此,现在的扩展
\bar
将是abc
,而 TeX 将检查\foo{def}
。这将与之前完全相同,但遵循“false”分支,因为\bar
不再是空的。所以我们将有\expandafter\g@addto@macro\foo@current@command{ def}
即成为
\g@addto@macro\bar{ def}
最终结果和我们说的一样
\def\bar{abc def}
首先。