expl3 具有参数化名称的属性列表序列:虚假空间

expl3 具有参数化名称的属性列表序列:虚假空间

编辑(上下文)

对于我正在研究的一个课程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}

相关内容