![expl3 具有参数化名称的属性列表序列:虚假空间](https://linux22.com/image/417444/expl3%20%E5%85%B7%E6%9C%89%E5%8F%82%E6%95%B0%E5%8C%96%E5%90%8D%E7%A7%B0%E7%9A%84%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8%E5%BA%8F%E5%88%97%EF%BC%9A%E8%99%9A%E5%81%87%E7%A9%BA%E9%97%B4.png)
编辑(上下文)
对于我正在研究的一个课程myclass
,我希望用户能够指定他所属的学院、下属学院、下属学院等(的特征)。由于(下属(下属(...)))学院的数量不可预测,我希望用户能够通过单个命令指定这些特征,例如\setinstitute
使用⟨key⟩ = ⟨value⟩
语法:
\setinstitute{
name = ⟨name⟩,
url = ⟨url⟩,
logo file = ⟨logo file⟩,
}
可以根据需要多次使用。
对于⟨key⟩ = ⟨value⟩
语法,我使用l3keys
模块及其良好的.prop_put:N
语法:
\keys_define:nn { myclass/institute }
{
name .prop_put:N = \l_tmpa_prop,
url .prop_put:N = \l_tmpa_prop,
logo~ file .prop_put:N = \l_tmpa_prop,
}
因此,机构的特征存储在属性列表中。
现在,指定机构的顺序应该表明每个机构的“深度”,我必须能够检索例如第 3 个机构的名称。因此,序列如下\g__myclass_institutes_seq
:
\NewDocumentCommand \setinstitute { m } {
\keys_set:nn { myclass/institute } { #1 }
\seq_gput_left:Nn \g__myclass_institutes_seq { \l_tmpa_prop }
}
重点是,始终使用相同的临时属性列表,并且序列仅包含最后输入的特征的多个副本。因此,在添加到序列之前,属性列表的变量名称与临时列表相等:
\int_new:N \g__myclass_institutes_number_int
\NewDocumentCommand \setinstitute { m } {
\keys_set:nn { myclass/institute } { #1 }
\int_gincr:N \g__myclass_institutes_number_int
\__myclass_populate_institutes_seq:n {
\int_use:N \g__myclass_institutes_number_int
}
}
\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
{
\prop_new:c {l__myclass_institute_#1_prop}
\prop_set_eq:cN {l__myclass_institute_#1_prop} \l_tmpa_prop
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The 3 following lines of code were wrong %
% and are replaced by the ones suggested by @egreg %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \seq_gput_left:Nn \g__myclass_institutes_seq {
% \l__myclass_institute_#1_prop
% }
\seq_gput_left:Nx \g__myclass_institutes_seq {
\exp_not:c {l__myclass_institute_#1_prop}
}
}
这是一个完整的例子:
\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
{myclass}
{2020/07/10}
{0.1}
{
My~Nice~Class.%
}
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }
%
\ExplSyntaxOn
\prop_new:N \l__myclass_institute_prop
\seq_new:N \g__myclass_institutes_seq
\int_new:N \g__myclass_institutes_number_int
\keys_define:nn { myclass/institute }
{
name .prop_put:N = \l_tmpa_prop,
url .prop_put:N = \l_tmpa_prop,
logo~ file .prop_put:N = \l_tmpa_prop,
}
\NewDocumentCommand \setinstitute { m } {
\keys_set:nn { myclass/institute } { #1 }
\int_gincr:N \g__myclass_institutes_number_int
\__myclass_populate_institutes_seq:n {
\int_use:N \g__myclass_institutes_number_int
}
}
\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
{
\prop_new:c {l__myclass_institute_#1_prop}
\prop_set_eq:cN {l__myclass_institute_#1_prop} \l_tmpa_prop
\prop_clear:N \l_tmpa_prop
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The 3 following lines of code were wrong %
% and are replaced by the ones suggested by @egreg %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \seq_gput_left:Nn \g__myclass_institutes_seq {
% \l__myclass_institute_#1_prop
% }
\seq_gput_left:Nx \g__myclass_institutes_seq {
\exp_not:c {l__myclass_institute_#1_prop}
}
}
\NewDocumentCommand \displayinstitutes { } {
\seq_reverse:N \g__myclass_institutes_seq
\seq_map_indexed_inline:Nn \g__myclass_institutes_seq {
\begin{description}
\item[Institute~##1:]\
% \prop_show:N ##2
\begin{description}
\prop_map_inline:Nn ##2 {
\item[####1:]####2
}
\end{description}
\end{description}
}
}
\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}
\documentclass{myclass}
\begin{document}
\setinstitute{
name = foo1,
url = bar1,
logo file = baz1,
}
\setinstitute{
name = foo2,
url = bar2,
logo file = baz2,
}
\displayinstitutes
\end{document}
但我在这里误用并非不可能expl3
。
原始帖子
我正在尝试创建一个expl3
属性列表序列,后者的名称被参数化(包含一个整数参数):。\l_#1_prop
借助说明符,可以轻松地将条目添加到此类属性列表中c
:
\prop_put:cnn {l_#1_prop} {key} {value}
因为\seq_put_left:Nc
不存在(并且不被接受为变体),我尝试将属性列表添加到序列中\l_#1_prop
:
\seq_put_left:Nn \l_tmpa_seq {
\l_#1_prop
}
但这会导致序列项为\l_ #1_prop
(注意虚假空格)而不是\l_#1_prop
。
以下 MCE 就是一个很好的例子:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \test { m m } {
\prop_new:c {l_#1_prop}
\prop_put:cnn {l_#1_prop} {key} {#2}
\seq_put_left:Nn \l_tmpa_seq {
\l_#1_prop
}
\prop_show:c {l_#1_prop}
\seq_show:N \l_tmpa_seq
}
\ExplSyntaxOff
\begin{document}
\test{1}{a}
\end{document}
所示的属性列表和序列分别给出\l_1_prop
和\l_ 1_prop
:
The property list \l_1_prop contains the pairs (without outer braces):
> {key} => {a}.
<recently read> }
l.17 \test{1}{a}
?
The sequence \l_tmpa_seq contains the items (without outer braces):
> {\l_ 1_prop}.
<recently read> }
l.17 \test{1}{a}
?
您知道杂散空间来自哪里以及如何消除它吗?
答案1
我认为没有必要将整个属性列表放在序列中:只需放置索引,当您需要从属性列表中检索某些内容时,您可以使用索引,例如
\prop_item:cn { l_ \seq_item:Nn \l_tmpa_tl {1} _ prop} } { foo }
为了foo
从属性列表中获取具有存储在序列第一个位置的索引的属性。
无论如何,如果你想存储全名,你可以这样做
\seq_put_left:Nx \l_tmpa_tl { \exp_not:c { l_#1_prop } }
你看到的不是虚假的空间。你正在将几个标记存储为序列项
\l_•1•_•p•r•o•p
\show
(项目符号只是为了清晰起见将标记分开)并且当被要求输入某个标记列表时,TeX 总是在控制字后添加一个空格。
更新
这是您的代码的编辑版本,我向其中展示了如何存储索引。
\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
{myclass}
{2020/07/10}
{0.1}
{
My~Nice~Class.
}
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }
\ExplSyntaxOn
\prop_new:N \l__myclass_institute_prop
\prop_new:N \l__myclass_tmpa_prop
\seq_new:N \g__myclass_institutes_seq
\int_new:N \g__myclass_institutes_number_int
\keys_define:nn { myclass/institute }
{
name .prop_put:N = \l__myclass_tmpa_prop,
url .prop_put:N = \l__myclass_tmpa_prop,
logo~ file .prop_put:N = \l__myclass_tmpa_prop,
}
\NewDocumentCommand \setinstitute { m }
{
\prop_clear:N \l__myclass_tmpa_prop
\keys_set:nn { myclass/institute } { #1 }
\int_gincr:N \g__myclass_institutes_number_int
\__myclass_populate_institutes_seq:V \g__myclass_institutes_number_int
}
\cs_new_protected:Npn \__myclass_populate_institutes_seq:n #1
{
\prop_new:c {l__myclass_institute_#1_prop}
\prop_set_eq:cN {l__myclass_institute_#1_prop} \l__myclass_tmpa_prop
\seq_gput_left:Nn \g__myclass_institutes_seq { #1 }
}
\cs_generate_variant:Nn \__myclass_populate_institutes_seq:n { V }
\NewDocumentCommand \displayinstitutes { }
{
\seq_set_eq:NN \l_tmpa_seq \g__myclass_institutes_seq
\seq_reverse:N \l_tmpa_seq
\seq_map_indexed_inline:Nn \l_tmpa_seq
{
\begin{description}
\item[Institute~##1:]\mbox{}
%\prop_show:c { l__myclass_institute_##2_prop }
\begin{description}
\prop_map_inline:cn { l__myclass_institute_##2_prop }
{
\item[####1:]####2
}
\end{description}
\end{description}
}
}
\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}
\documentclass{myclass}
\begin{document}
\setinstitute{
name = foo1,
url = bar1,
logo file = baz1,
}
\setinstitute{
name = foo2,
url = bar2,
logo file = baz2,
}
\displayinstitutes
\end{document}
但是,由于索引只是一个在每次调用时递增的数字\setinstitute
,因此您甚至不需要序列:只需通过索引调用属性列表。
\begin{filecontents*}[overwrite]{myclass.cls}
\RequirePackage{l3keys2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\ProvidesExplClass
{myclass}
{2020/07/10}
{0.1}
{
My~Nice~Class.
}
\NeedsTeXFormat{LaTeX2e}
\LoadClass { article }
\ExplSyntaxOn
\prop_new:N \l__myclass_institute_prop
\prop_new:N \l__myclass_tmpa_prop
\int_new:N \g__myclass_institutes_number_int
\keys_define:nn { myclass/institute }
{
name .prop_put:N = \l__myclass_tmpa_prop,
url .prop_put:N = \l__myclass_tmpa_prop,
logo~ file .prop_put:N = \l__myclass_tmpa_prop,
}
\NewDocumentCommand \setinstitute { m }
{
\prop_clear:N \l__myclass_tmpa_prop
\keys_set:nn { myclass/institute } { #1 }
\int_gincr:N \g__myclass_institutes_number_int
\prop_new:c {l__myclass_institute_ \int_use:N \g__myclass_institutes_number_int _prop}
\prop_set_eq:cN
{l__myclass_institute_ \int_use:N \g__myclass_institutes_number_int _prop}
\l__myclass_tmpa_prop
}
\NewDocumentCommand \displayinstitutes { }
{
\int_step_inline:nn { \g__myclass_institutes_number_int }
{
\begin{description}
\item[Institute~##1:]\mbox{}
%\prop_show:c { l__myclass_institute_##1_prop }
\begin{description}
\prop_map_inline:cn { l__myclass_institute_##1_prop }
{
\item[####1:]####2
}
\end{description}
\end{description}
}
}
\ProcessKeysOptions { myclass }
\ExplSyntaxOff
\end{filecontents*}
\documentclass{myclass}
\begin{document}
\setinstitute{
name = foo1,
url = bar1,
logo file = baz1,
}
\setinstitute{
name = foo2,
url = bar2,
logo file = baz2,
}
\displayinstitutes
\end{document}