我想使用 来处理数据结构expl3
。此数据结构将按照以下格式从文件读取和写入文件.aux
(这是我的提议 - 当然,我愿意接受更好的建议):
\my@load@command{%
\my@start@key{keyA}%
\my@additem{item1}%
\my@additem{item2}%
(...)
\my@additem{itemn}%
\my@stop@key
\my@start@key{keyB}%
\my@additem{item1}%
\my@additem{item2}%
(...)
\my@additem{itemn}%
\my@stop@key
(...)
\my@stop@key
}
此代码表示的数据结构是从字符串到字符串列表的映射。换句话说,每个键都是一个唯一的字符串,并映射到一个项目列表,其中每个项目本身都是一个字符串(按照 LaTeX3 的类型str
)。我的代码将确保对于给定的键,列表中的所有项目都是唯一的(但它们的顺序很重要,因此这不是“集合语义”)。
我的问题是如何使用当前的 LaTeX3 工具集以“最佳方式”对此进行建模。
第一种可能性
有一个全局属性列表(来自l3prop
),其中每个键都映射到一个 〈balanced text〉,该列表使用分隔符(例如\q_nil
或逗号)描述关联的项目列表(在后一种情况下,为了一般性,每个 〈balanced text〉 都可以是这种形式,并且我认为{〈item〉},{〈item〉},...,{〈item〉}
可以将其变成seq
使用)。\seq_set_from_clist:Nn
这意味着当需要为给定的键添加一个项目时:
\seq_set_split:Nnn
首先,我们从全局属性列表中检索相应的值作为 〈balanced text〉 标记列表,然后使用或将其转换为序列\seq_set_from_clist:Nn
;如果该项目尚不存在,我们就将其附加到序列中;
最后,如果这确实是一个新项目,我们将结果项目列表写入全局属性列表(作为与我们正在处理的键关联的值)。
这些操作可能有点慢,但是这种方法似乎不会浪费寄存器等潜在的稀缺资源。
第二种可能性
有一个序列或逗号列表来存储迄今为止看到的键列表,并且每当我们向该列表添加新键时,使用类似以下内容创建关联序列:
\seq_new:c { g__my_list_of_items_for_ #1 }
其中#1
代表键名称。
这样,操作给定键的项目列表就很容易了,但是我们创建每个键一个序列变量文档中可以看到。例如,给定文档中可能会有几千个键,理论上,多个包可能正在执行相同的操作。这是对 TeX 资源的正确使用吗?例如,如果每个seq
变量都存储在 TeX 寄存器中,1在我看来,考虑到寄存器的数量有限(这可能取决于引擎和用于此目的的寄存器的精确类型,但如果是这种情况,我认为我更喜欢一种仅受“软参数”限制的方法,例如TeX 实现的number of strings
、pool size
和)。hash size
底线:第二种方法有一些优点,但由于不知道seq
变量在 LaTeX3 中是如何实现的,所以我不知道它是否能很好地扩展。
脚注
- 我不知道是否是这样。
答案1
这是原型。序列实际上是宏,因此它们只会影响字符串和哈希表的内存。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\keyadd}{mm}
{
\seq_if_exist:cF { g_my_items_for_#1_seq }
{
\seq_gput_right:Nn \g_my_keys_seq { #1 } % the list of keys
\seq_new:c { g_my_items_for_#1_seq }
}
\seq_gput_right:cn { g_my_items_for_#1_seq } { #2 }
}
\seq_new:N \g_my_keys_seq
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
\cs_new_protected:cpn { my@define@key } #1 #2
{
\seq_gput_right:Nn \g_my_keys_seq { #1 } % the list of keys
\__my_key_new:n { #1 }
\seq_set_split:cnn { g_my_items_for_#1_seq } { } { #2 }
}
\cs_new_protected:Nn \__my_key_new:n
{
\seq_new:c { g_my_items_for_#1_seq }
}
\cs_new:Nn \__my_write_key:n
{
\token_to_str:N \my@define@key { #1 }
{
^^J
\seq_map_function:cN { g_my_items_for_#1_seq } \__my_write_item:n
}
^^J
}
\cs_new:Nn \__my_write_item:n { {#1} ^^J }
\AtEndDocument
{
\cs_set_eq:NN \__my_key_new:n \use_none:n
\iow_now:cx { @auxout } { \seq_map_function:NN \g_my_keys_seq \__my_write_key:n }
}
\ExplSyntaxOff
\begin{document}
Some text
\keyadd{keyA}{item1}
\keyadd{keyA}{item2}
\keyadd{keyA}{item3}
\keyadd{keyA}{item4}
\keyadd{keyA}{item5}
\keyadd{keyA}{item6}
\keyadd{keyA}{item7}
\keyadd{keyB}{item1}
\keyadd{keyB}{item2}
\keyadd{keyB}{item3}
\keyadd{keyB}{item4}
\end{document}
该.aux
文件将包含
\relax
\my@define@key{keyA}{
{item1}
{item2}
{item3}
{item4}
{item5}
{item6}
{item7}
}
\my@define@key{keyB}{
{item1}
{item2}
{item3}
{item4}
}