![如何使用 \def 或类似命令存储任意数量的变量以供稍后处理?](https://linux22.com/image/236642/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20%5Cdef%20%E6%88%96%E7%B1%BB%E4%BC%BC%E5%91%BD%E4%BB%A4%E5%AD%98%E5%82%A8%E4%BB%BB%E6%84%8F%E6%95%B0%E9%87%8F%E7%9A%84%E5%8F%98%E9%87%8F%E4%BB%A5%E4%BE%9B%E7%A8%8D%E5%90%8E%E5%A4%84%E7%90%86%EF%BC%9F.png)
我正在尝试创建一个使用 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
。
(但正如马修所说,这可能不是做你想做的事情的最简单的方法......)