假设我想定义一个命令\defineaspect
,该命令采用键/值选项列表来将值与事先未知的键关联起来。例如,要将某些方面与人员列表关联起来,该命令的使用可能看起来像
\defineaspect{forename}{
.print = {},
sherlock = Sherlock,
jim = James
}
\defineaspect{surname}{
.print = \scshape,
sherlock = Holmes,
jim = Moriarty
}
sherlock
然后jim
应将其视为数据库表中的主键,各个方面是该表中的进一步列。此外,一些实际预定义的键也可能出现在此列表中,如.print
示例中所示。
我浏览了一些用于键/值处理的包,但据我所知,拥有大量非预定义键并不是这些包的典型用例。
是否有一个键/值包可以轻松处理此类键?或者我最好使用自定义解析器,先拆分列表,
,然后分别解析每个键/值对?
答案1
您可以利用expl3
的键值系统和prop
数据类型。要将键值列表转换为expl3
属性列表,您可以使用\prop_set_from_keyval:Nn
。该函数将获取key = value
中的每个对#2
并添加到prop
中的列表中#1
。本例中的示例文档如下:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \defineaspect { mm }
{
\prop_new:c { g__siracusa_#1_aspect_prop }
\prop_gset_from_keyval:cn { g__siracusa_#1_aspect_prop } {#2}
}
%
\tl_new:N \l__siracusa_tmpa_tl
\NewDocumentCommand \getaspect { mm }
{
\prop_get:cnNTF { g__siracusa_#1_aspect_prop } {#2} \l__siracusa_tmpa_tl
{ \tl_use:N \l__siracusa_tmpa_tl }
{ Aspect~#2~does~not~exist~in~#1! }
}
\NewDocumentCommand \fullname { m }
{
{ \getaspect { forename } { .print } \getaspect { forename } {#1} ~ }
{ \getaspect { surname } { .print } \getaspect { surname } {#1} }
}
\ExplSyntaxOff
\defineaspect{forename}{
.print = {},
sherlock = Sherlock,
jim = James
}
\defineaspect{surname}{
.print = \scshape,
sherlock = Holmes,
jim = Moriarty
}
\begin{document}
Did you miss me? --- \fullname{jim}
\end{document}
但是,这会将输入一对一地转换为数据结构。如果您需要更精细地控制该过程,例如,区分简单键、键和“特殊”键,例如.print
,那么您可以使用\keyval_parse:NNn
。
\keyval_parse:NNn
接受两个函数和一个键值列表作为参数。\keyval_parse:NNn
遍历键值列表,#3
并对列表的每个项目使用函数#1
或,#2
具体取决于项目是否只有一个键或一个键和一个值。
上述内容的重新实施\defineaspect
将变为:
\prop_new:N \l__siracusa_tmpa_prop
\NewDocumentCommand \defineaspect { mm }
{
\prop_clear:N \l__siracusa_tmpa_prop
\keyval_parse:NNn \__siracusa_aspect:n \__siracusa_aspect:nn {#2}
\prop_new:c { g__siracusa_#1_aspect_prop }
\prop_gset_eq:cN { g__siracusa_#1_aspect_prop } \l__siracusa_tmpa_prop
}
\cs_new_protected:Npn \__siracusa_aspect:n #1
{ \__kernel_msg_error:nnn { kernel } { prop-keyval } {#1} }
\cs_new_protected:Npn \__siracusa_aspect:nn #1#2
{ \prop_put:Nnn \l__siracusa_tmpa_prop {#1} {#2} }
定义中的错误消息\__siracusa_aspect:n
只是为了模仿的行为\prop_set_from_keyval:Nn
,但当然,当仅给出一个键时,您可以将其更改为适当的操作。