假设我有 100 个节点,我想绘制 100 次,每次都略有变化。我不想每次都复制/粘贴所有代码,那会造成大量重复和大量样板代码。因此,我正在考虑制作一个紧凑的数据结构来保存这些值。
问题是,用 Latex 的方式实现这个无需解析也就是说,如果不为自定义数据结构编写自定义解析器,如何实现这一点。
需要解析的示例数据结构如下:
\mynodes{1:red,2:blue,3:yellow,....}
这将为您提供一个以逗号分隔的列表id:color
,然后您可以对其进行解析。
不过,我想知道是否有一种方法可以不进行解析就做到这一点。例如(假设存在 100 个属性1-100
):
\mynodes{1=red,2=yellow}
但这个例子太简单了,每个 id 可能会有多个值。所以更像是:
\mynodes{1=\keys{color=red,size=1cm},2=\keys{color=yellow,size=1cm},...}
如果您有一个属性和值的查找表,则可以缩短此过程,例如:
\mynodes{1=\v{c=r,s=1},2=\v{c=y,s=1},...}
然后,这将为您提供一个etoolbox
要迭代的对象列表。想知道这样的事情是否可行,并阐明如何实现这一点。
最终结果将是更紧凑的数据结构,无需使用任何解析。
答案1
我建议一种expl3
方法。我们将节点数据存储在属性列表中;对于节点 1,属性1
将包含整个数据集;我们还为特定数据添加属性1color
和。1size
可以使用 检索数据\getmynode
。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\mynodes}{m}
{
\prop_set_from_keyval:Nn \l_pollard_nodes_prop { #1 }
\prop_map_inline:Nn \l_pollard_nodes_prop { \pollard_add_property:nn { ##1 } { ##2 } }
}
\NewExpandableDocumentCommand{\getmynode}{mm}
{% #1 = node number, #2 = property
\prop_item:Nn \l_pollard_nodes_prop { #1#2 }
}
\keys_define:nn { pollard/nodes }
{
color .code:n = \prop_put:Nxn \l_pollard_nodes_prop { \l__pollard_nodes_temp_tl color } { #1 },
size .code:n = \prop_put:Nxn \l_pollard_nodes_prop { \l__pollard_nodes_temp_tl size } { #1 },
}
\prop_new:N \l_pollard_nodes_prop
\cs_generate_variant:Nn \prop_put:Nnn { Nx }
\cs_new_protected:Nn \pollard_add_property:nn
{
\tl_set:Nn \l__pollard_nodes_temp_tl { #1 }
\keys_set:nn { pollard/nodes } { #2 }
}
\ExplSyntaxOff
\begin{document}
\mynodes{1={color=red,size=1cm},2={color=yellow,size=2cm},}
Node 1 -- color: \getmynode{1}{color}, size: \getmynode{1}{size}
Node 2 -- color: \getmynode{2}{color}, size: \getmynode{2}{size}
\end{document}
简写形式:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\mynodes}{m}
{
\prop_set_from_keyval:Nn \l_pollard_nodes_prop { #1 }
\prop_map_inline:Nn \l_pollard_nodes_prop { \pollard_add_property:nn { ##1 } { ##2 } }
}
\NewExpandableDocumentCommand{\getmynode}{mm}
{% #1 = node number, #2 = property
\prop_item:Nn \l_pollard_nodes_prop { #1#2 }
}
\keys_define:nn { pollard/nodes }
{
color .code:n = \prop_put:Nxn \l_pollard_nodes_prop { \l__pollard_nodes_temp_tl color } { #1 },
size .code:n = \prop_put:Nxn \l_pollard_nodes_prop { \l__pollard_nodes_temp_tl size } { #1 },
c .code:n = \prop_put:Nxx \l_pollard_nodes_prop
{ \l__pollard_nodes_temp_tl color }
{ \__pollard_nodes_color:n { #1 } },
s .code:n = \keys_set:nn { pollard/nodes } { size=#1cm }
}
\prop_new:N \l_pollard_nodes_prop
\cs_generate_variant:Nn \prop_put:Nnn { Nxn, Nxx }
\cs_new_protected:Nn \pollard_add_property:nn
{
\tl_set:Nn \l__pollard_nodes_temp_tl { #1 }
\keys_set:nn { pollard/nodes } { #2 }
}
\cs_new:Nn \__pollard_nodes_color:n
{
\str_case:nn { #1 }
{
{r}{red}
{y}{yellow}
% define the others you need
}
}
\ExplSyntaxOff
\begin{document}
\mynodes{1={color=red,size=1cm},2={color=yellow,size=2cm},}
Node 1 -- color: \getmynode{1}{color}, size: \getmynode{1}{size}
Node 2 -- color: \getmynode{2}{color}, size: \getmynode{2}{size}
\mynodes{3={c=r,s=1}}
Node 3 -- color: \getmynode{3}{color}, size: \getmynode{3}{size}
\end{document}
答案2
如果您想尽可能避免解析,并且所有值都具有相同的属性列表,您可以让 TeX 使用宏调用列表作为参数来解析您的输入:
\documentclass{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\newcommand\mynodes[1]{%
\begingroup
\renewcommand\do[3]{%
Node ##1 has color ``##2'' and size ``##3''.\\%
}%
#1%
\endgroup
}
\begin{document}
\mynodes{\do{1}{red}{1cm}\do{2}{yellow}{1cm}}
\end{document}
答案3
我不完全确定您需要解析到什么级别\keys
,但我确信该listofitems
包可以为您解析它。
\documentclass{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{listofitems}
\newcommand\mynodes[1]{%
\setsepchar{,/=}
\readlist\mynodelist{#1}%
\foreachitem\x\in\mynodelist{%
node \mynodelist[\xcnt,1] is as follows:
\detokenize\expandafter\expandafter\expandafter{\mynodelist[\xcnt,2]}%
\par%
}%
}
\begin{document}
\mynodes{1=\keys{color=red,size=1cm},2=\keys{color=yellow,size=1cm}}
\end{document}
例如,进一步解析键:
\documentclass{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{listofitems}
\newcommand\mynodes[1]{%
\setsepchar{,/=}
\readlist\mynodelist{#1}%
\foreachitem\x\in\mynodelist{%
node \mynodelist[\xcnt,1] is as follows:\\
\expandafter\expandafter\expandafter\parsekeys\mynodelist[\xcnt,2]%
\readlist\keylist{\tmp}%
\foreachitem\y\in\keylist{The key ``\keylist[\ycnt,1]''
has a value of ``\keylist[\ycnt,2]''.\\}%
\par%
}%
}
\def\parsekeys\keys#1{\gdef\tmp{#1}}
\begin{document}
\mynodes{1=\keys{color=red,size=1cm},2=\keys{color=yellow,size=1cm}}
\end{document}
\keys
如果您避免在节点列表中支撑实际内容,那么listofitems
可以更轻松地一举完成,而不是像\readlist
我的第二个代码块中所示的那样嵌套。
因此,以下代码使用输入语法也会产生上述结果\mynodes{1:color=red,size=1cm;2:color=yellow,size=1cm}
:
\documentclass{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{listofitems}
\newcommand\mynodes[1]{%
\setsepchar{;/:/,/=}
\readlist\mynodelist{#1}%
\foreachitem\x\in\mynodelist{%
node \mynodelist[\xcnt,1] is as follows:\\
\foreachitem\y\in\mynodelist[\xcnt]{The key
``\mynodelist[\xcnt,2,\ycnt,1]''
has a value of ``\mynodelist[\xcnt,2,\ycnt,2]''.\\%
}%
\par%
}%
}
\begin{document}
\mynodes{1:color=red,size=1cm;2:color=yellow,size=1cm}
\end{document}
通过上述代码中的单个操作\readlist
,所有输入都会立即存储在数组中\mynodelist
。
\mynodelist[<node-number>,2,<key number>, 1]
给出关联的密钥,并
\mynodelist[<node-number>,2,<key number>, 2]
给出相关的键值。