将文本经过 \keys_define 后拆分为列表

将文本经过 \keys_define 后拆分为列表

我正在尝试创建一个带有键值参数的命令,其中第二个参数是用逗号分隔的项目列表。

当我将列表直接传递给命令时,该列表可以正常打印\DrawList,该命令具有\SplitList处理器和\ProcessList命令。但是,如果在拆分之前对文本进行解析\keys_define,它似乎会忽略逗号,处理器根本无法拆分它。

我怎样才能让它像\DrawList命令一样打印?如果有人有更好的替代方案来简化界面,那就太好了。谢谢大家。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\usepackage{enumitem}
\NewDocumentCommand\DrawList{>{\SplitList{,}}m}{
    \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
        \ProcessList{#1}{\item}
    \end{itemize}
}

\keys_define:nn {module_name}{
    ,1 .tl_set:N  = \__title
    ,2 .tl_set:N  = \__list
}

\NewDocumentCommand \TitleAndList {O{}}{
    \group_begin:
    \keys_set:nn {module_name}{#1}
    \tl_if_empty:NF {\__title}{%
        \__title :\par
    }
    \tl_if_empty:NF {\__list}{%
        \DrawList{\__list}
    }
    \group_end:
}

\ExplSyntaxOff


\begin{document}

\DrawList{{First item, with a comma}, {Second item}}

---

\TitleAndList[
    1=Include,
    2={{First item, with a comma}, {Second item}}
]

---

\TitleAndList[1=Not a list]

---

\TitleAndList[2=An item]

\end{document}

结果:

结果

低层代码没有成功:

\seq_new:N \list_sequence
\NewDocumentCommand\DrawList{m}{
    \seq_set_split:Nnn \list_sequence{,}{#1}
    \begin{itemize}
        \seq_map_function:NN \list_sequence \item
    \end{itemize}
}

答案1

由于唯一一次使用\DrawList包含列表的变量进行调用是在您自己的代码内部,因此您可以简单地使用\exp_args:NV\exp_args:No(如果您知道该变量是一个标记列表,则后者就可以了)。

如果您还希望用户界面宏能够对存储列表的宏进行操作,那么您可以定义自己的处理器。

下面的操作同时执行,改变您的\TitleAndList以扩展您转发的变量\DrawList并定义一个处理器并将其用于\otherDrawList

请注意,您的变量应遵循 的命名约定expl3,即局部变量(如您的变量)应以 开头\l,内部变量应有两个下划线,后跟模块名称、变量的简短描述,并以缩写的变量类型结尾。因此,以下是正确的名称:(\l__thanhph_title_tl模块的局部变量thanhph存储名为 的内容title,它是一个标记列表)。

\documentclass{article}

\usepackage{enumitem}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new_protected:Npn \thanhphSplitList #1 #2
  {
    \tl_if_single_token:nTF {#2}
      {
        \tl_if_head_is_space:nTF {#2}
          { \SplitList {#1} {#2} }
          {
            \token_if_expandable:NTF #2
              { \exp_args:Nno \SplitList {#1} {#2} }
              { \SplitList {#1} {#2} }
          }
      }
      { \SplitList {#1} {#2} }
  }

\NewDocumentCommand \otherDrawList { >{\thanhphSplitList{,}}m }
  {
    \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
      \ProcessList{#1}{\item}
    \end{itemize}
  }

\NewDocumentCommand \DrawList { >{\SplitList{,}}m }
  {
    \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
      \ProcessList{#1}{\item}
    \end{itemize}
  }

\keys_define:nn { thanhph }
  {
    ,1 .tl_set:N  = \l__thanhph_title_tl
    ,2 .tl_set:N  = \l__thanhph_list_tl
  }

\NewDocumentCommand \TitleAndList {O{}}
  {
    \group_begin:
      \keys_set:nn { thanhph } {#1}
      \tl_if_empty:NF \l__thanhph_title_tl
        { \l__thanhph_title_tl :\par }
      \tl_if_empty:NF \l__thanhph_list_tl
        { \exp_args:No \DrawList \l__thanhph_list_tl }
    \group_end:
  }

\ExplSyntaxOff


\newcommand\mylist{one item, another item}

\begin{document}

\otherDrawList\mylist

---

\DrawList{{First item, with a comma}, {Second item}}

---

\TitleAndList[
    1=Include,
    2={{First item, with a comma}, {Second item}}
]

---

\TitleAndList[1=Not a list]

---

\TitleAndList[2={An item, another}]

\end{document}

在此处输入图片描述

另一种解决方案是,如果您想扩展强制参数的第一个标记一次,则可以使用带星号的形式。我们可以相当巧妙地创建它,因为ltcmd/xparse允许引用处理器内的其他参数,因此我们可以将其用作\IfBooleanT{#1}\exp_args:Nno\SplitList{,}处理器:

\NewDocumentCommand \DrawList
  { s >{ \IfBooleanT {#1} \exp_args:Nno \SplitList {,} } m }
  {
    \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
      \ProcessList{#2}{\item}
    \end{itemize}
  }

然后使用

\DrawList*\mylist

获得与 相同的结果\otherDrawList\mylist


如果您根本不需要\DrawList而只打算用作\TitleAndUse接口,则可以直接映射到clist(前提是您不需要将列表作为令牌列表并且这是唯一的预期用途):

\documentclass{article}

\usepackage{enumitem}
\usepackage{xparse}

\ExplSyntaxOn

\keys_define:nn { thanhph }
  {
    ,1 .tl_set:N  = \l__thanhph_title_tl
    ,2 .clist_set:N  = \l__thanhph_list_clist
  }

\NewDocumentCommand \TitleAndList {O{}}
  {
    \group_begin:
      \keys_set:nn { thanhph } {#1}
      \tl_if_empty:NF \l__thanhph_title_tl
        { \l__thanhph_title_tl :\par }
      \clist_if_empty:NF \l__thanhph_list_clist
        { \__thanhph_typeset_list: }
    \group_end:
  }
\cs_new_protected:Npn \__thanhph_typeset_list:
  {
    \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
      \item % one \item in front of the first clist element
      \clist_use:Nn \l__thanhph_list_clist \item % and one \item in front of the rest
    \end{itemize}
  }

\ExplSyntaxOff


\newcommand\mylist{one item, another item}

\begin{document}

\TitleAndList[
    1=Include,
    2={{First item, with a comma}, {Second item}}
]

---

\TitleAndList[1=Not a list]

---

\TitleAndList[2={An item, another}]

\end{document}

@egreg 的回答此方法的较短版本。

答案2

如果您希望将 clist 作为键的值,请按此方式定义它。

\documentclass{article}
\usepackage{enumitem}
%\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand\DrawList{m}
 {
  \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
  \clist_map_inline:nn { #1 } { \item ##1 }
  \end{itemize}
 }

\keys_define:nn { thanhph/lists }
 {
  1 .tl_set:N    = \l__thanhph_lists_title_tl,
  2 .clist_set:N = \l__thanhph_lists_list_clist,
}

\NewDocumentCommand \TitleAndList {O{}}
 {
  \group_begin:
  \keys_set:nn { thanhph/lists } { #1 }
  \tl_if_empty:NF \l__thanhph_lists_title_tl 
   {
    \l__thanhph_lists_title_tl \par
   }
   \clist_if_empty:NF \l__thanhph_lists_list_clist
    {
     \begin{itemize}[leftmargin=*, noitemsep, topsep=0pt]
     \clist_map_inline:Nn \l__thanhph_lists_list_clist { \item ##1 }
     \end{itemize}
    }
  \group_end:
 }
\ExplSyntaxOff


\begin{document}

\subsubsection*{Just the list}

\DrawList{{First item, with a comma}, {Second item}}

\subsubsection*{Title and list}

\TitleAndList[
    1=Include,
    2={{First item, with a comma}, {Second item}}
]

\subsubsection*{Only title}

\TitleAndList[1=Not a list]

\subsubsection*{Only list}

\TitleAndList[2={An item,Another item}]

\end{document}

在此处输入图片描述

相关内容