创建另一个具有自定义名称的宏的宏

创建另一个具有自定义名称的宏的宏

我想创建一个宏,该宏会在通过宏\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定义包装器命令的部分作为初始化的当前宏。

最后一组宏是如何工作的?让我们以慢动作来看一下。

  1. 这里是\defcommand

    \newcommand{\defcommand}[1]{%
      \gdef#1{}%
      \gdef\foo@current@command{#1}%
    }
    

    如果我们说\defcommand{\mymacro}效果将是初始化\mymacro为具有空扩展。那么(全局)定义将使其\foo@current@command扩展为\mymacro(而不是的内容\mymacro,至少在第一次扩展时)。

  2. 以下是\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}
    

    它可以完成所需的任务。

  3. 使用更复杂的定义来确保我们添加的第一个项前面没有添加空格:

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

    首先。

相关内容