如何使用 \def 或类似命令存储任意数量的变量以供稍后处理?

如何使用 \def 或类似命令存储任意数量的变量以供稍后处理?

我正在尝试创建一个使用 PGF/TikZ 绘制简单序列图的包。这是我坚持的基本想法(为了简短,不是全部想法):

假设我们有 1 个环境(比如诊断工具)和 1 个命令(例如创建对象) 在此包中。

用户将按如下方式使用它们:

\begin{myseqdiag}
\createobject{my name is A} 
\createobject{my name is B}
  %<here, other calls to createobject>
\end{myseqdiag}

调用命令 createobject 会导致计数器对象计数器增加,并存储#1(希望)在一个名为 obja 的变量中(如果 TeX/LaTeX 中有“变量”这样的东西)。

在环境端,代码应该使用最终计数并使用存储的“变量”(“我的名字是 A”,“我的名字是 B”......)来绘制对象(生命线)。

问题是我无法存储这些参数。

我试过

\def\obj\alph{objcounter}{#1}

在 createobject 的代码里面,希望它能够定义 obja、objb、...,但是它不起作用。

我也尝试了其他变体,但是没有效果。

我是 LaTeX 新手,不了解编程语言中的变量和数组概念。那么,有办法解决我的问题吗?

在此先感谢您的帮助。

答案1

我缺少编程语言中的变量和数组的概念......

TeX 允许您定义自己的数据结构,关联数组是内置的。您可以将宏视为关联数组。

通常,我会采用两步方法来处理您所描述的任务。

首先定义一个列表例如\def\alist{foo,bar,beer}

其次,当您使用其他海报描述的自动方式之一定义命令时,您也会将名称添加到列表中。

这样,您就可以遍历列表,并有效地创建了一个数组objects。请参见下面的极简图。

   \documentclass{article}
    \usepackage{pgfplots}
    \begin{document}
    \makeatletter
    \gdef\alist{john,}
    \def\addtolist#1#2{\g@addto@macro{#1}{#2,}}
    \def\CommandFactory#1#2{%
      \expandafter\def\csname#1\endcsname{#2}
      \addtolist{\alist}{#1}
    }
    \CommandFactory{George}{George's commands}
    \CommandFactory{Mary}{Mary's commands}
    \CommandFactory{foo}{foo commands}
    \CommandFactory{bar}{\tikzpicture
        \axis[stack plots=y]
        \addplot coordinates
            {(0,1) (1,1) (2,2) (3,2)};
        \addplot coordinates
            {(0,1) (1,1) (2,2) (3,2)};
        \addplot coordinates
            {(0,1) (1,1) (2,2) (3,2)};
        \endaxis
    \endtikzpicture}

    %loop through all the records
    \@for \i:=\alist \do{%
      \@nameuse{\i}

    }

    \makeatother
    \end{document}

我把代码保持在最低限度以使其更加清晰。

答案2

我发现您有多个问题 - 我将尝试回答其中一些:

让我们从简单的开始:TeX 知道变量(尽管它们与其他语言中了解的变量不同)。但它实际上对数组一无所知,尽管有一些包可以通过 TeX 数组模拟数组。此说明适用于 TeX,因为它已经存在多年了——新的 LuaTeX 项目可能会改变这一点。

无论如何,有一个方法可以解决您的问题:

\setcounter{objcounter}{1}
\def\createobj#1{%
    \expandafter\def\csname obj\alph{objcounter}\endcsname{#1}
}
\createobj{Something}

可以完成这项工作。重点是\expandafter:它改变了执行顺序,这样当 TeX 看到时\expandafter,它将查看紧随其后的标记\def并扩展其后的内容。在我们的例子中,有\csname obj\alph{objcounter}\endcsname。这扩展为“控制序列名称”,即\obja(因为\alph{objcounter}扩展为a)。然后,\expandafter从输入列表中删除,TeX 只会看到\def\obja{#1}您想要的内容。

您可能想要阅读有关所有这些命令的更多文献(见下文)。

请注意,这里不需要\alph。事实上,使用数字索引可能更合适(但这取决于您)。

当我学习 TeX 时,我发现很难找到好的(免费)资源。在我看来,最好的资源是 Donald Knuth 的 TeXbook(我相信它的源代码在特定条件下可以在线获取?)。我还找到了一本免费的 TeX 书(但不幸的是它是德文的;它的链接在下面列出的 TeX-Programming-Notes.pdf 中)。

由于我更多地从事编程(也使用 TikZ/pgf)而不是排版,因此我开始收集 TeX 编程笔记,特别是关于细粒度扩展控制(\expandafter只是 TeX 的扩展控制机制之一)。如果您有兴趣,您可以查看“TeX-Programming-Notes.pdf”,可在http://pgfplots.sourceforge.net

答案3

为了解决眼前的问题,有一种方法可以定义一个名称可以更改的命令。原\csname语适用于这种情况。您可以执行以下操作:

\expandafter\def\csname obj\alph{objcounter}\endcsname{#1}

在您的命令中。当您想使用这些命令时,请使用相同的语法:

\csname obj\alph{objcounter}\endcsname

注意:后面的空格\csname纯粹是为了标记命令的结束\csname,并且在 - 之前没有反斜杠,obj这是由 隐式地放在那里的\csname

(但正如马修所说,这可能不是做你想做的事情的最简单的方法......)

相关内容