定义具有多个可选参数的列表环境

定义具有多个可选参数的列表环境

我正在尝试定义一个list具有多个可选参数的环境,并为这些参数设置默认值。例如,创建一个名为newenv,它接受两个参数,如果不存在则使用默认值:

\documentclass{article}
\usepackage{array}
\usepackage{multicol}
\usepackage{enumerate}

\begin{document}

\newenvironment{newenv}[2][2]
{\begin{multicols}[#1]\begin{enumerate}[#2]}
{\end{enumerate}\end{multicols}}

\begin{newenv}{2}{2}
  \item a
  \item b
  \item c
  \item d
\end{newenv}

\end{document}

我错过了什么?

答案1

我会用enumitem包 - 它简化了语法并为我们完成了繁重的工作

第一部分是设置一个新的列表环境

\newlist{newenv}{enumerate}{5}
\setlist[newenv]{label=\arabic*.}

其默认标签为1., 2., 等

然后我们设置一个新密钥,columns

\SetEnumitemKey{columns}{before=\begin{multicols}{#1},
                         after=\end{multicols}}

这使我们能够使用各种组合,如下面的 MWE 所示

截屏

\documentclass{article}
\usepackage{enumitem}
\usepackage{multicol}

\newlist{newenv}{enumerate}{5}
\setlist[newenv]{label=\arabic*.}

\SetEnumitemKey{columns}{before=\begin{multicols}{#1},
                                               after=\end{multicols}}

\begin{document}
\begin{newenv}[label=\roman*),columns=4]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[columns=3]
\item a
\item b
\item c
\end{newenv}

\hrule

\begin{newenv}[label=\roman*)]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[label*=(A\arabic*),columns=3]
\item a
\item b
\item c
\item d
\item e
\item f
\end{newenv}

\end{document}

答案2

我同意 Werner 的观点,认为多个可选参数应该用键值语法代替。下面是一种方法:

\documentclass{article}
\usepackage{enumerate,multicol,xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{newenv}{ O{} }
 {
  \keys_set:nn { aksr/newenv }
   {
    #1           % use the options
   }
  \int_compare:nT { \l__aksr_columns_tl > 1 } % more than one column
   { \begin{multicols}{ \l__aksr_columns_tl } }
  % We must pass the optional argument expanded
  \use:x { \exp_not:N \begin{enumerate}[ \l__aksr_label_tl ] }
 }
 {
  \end{enumerate}
  \int_compare:nT { \l__aksr_columns_tl > 1 }
   { \end{multicols} }
 }

\tl_new:N \l__aksr_columns_tl
\tl_new:N \l__aksr_label_tl

\keys_define:nn { aksr/newenv }
 {
  columns .tl_set:N  = \l__aksr_columns_tl,
  columns .initial:n = 2,
  label   .tl_set:N  = \l__aksr_label_tl,
  label   .initial   = 1.,
 }
\ExplSyntaxOff

\begin{document}
\begin{newenv}
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[columns=1]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[label=i)]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[label=(A),columns=3]
\item a
\item b
\item c
\item d
\item e
\item f
\end{newenv}

\end{document}

一旦我们掌握了它,它就相当简单了。唯一的微妙之处在于我们必须将参数传递给\begin{enumerate}expanded,而不是标记列表变量,所以这\use:x能起到作用。

这两个键只是将值存储在一个标记列表变量中以供以后使用。默认值只需在评估可选参数之前给出值即可建立newenv

您可以考虑领养enumitem而不是enumerate

在此处输入图片描述


下面是一个不同的版本,它可以使用enumitem并展示“未知”键的使用方法:

\documentclass{article}
\usepackage{enumitem,multicol,xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{newenv}{ O{} }
 {
  % clear the options passed to enumitem
  \tl_clear:N \l__aksr_enumitem_tl
  \keys_set:nn { aksr/newenv }
   {
    #1 % use the options
   }
  \int_compare:nT { \l__aksr_columns_tl > 1 } % more than one column
   { \begin{multicols}{ \l__aksr_columns_tl } }
  % We must pass the optional argument expanded; we append
  % the label key and value to the other possibly set options
  \tl_put_right:Nn \l__aksr_enumitem_tl { label = }
  \tl_put_right:NV \l__aksr_enumitem_tl \l__aksr_label_tl
  \aksr_beginenum:V \l__aksr_enumitem_tl 
 }
 {
  \end{enumerate}
  \int_compare:nT { \l__aksr_columns_tl > 1 }
   { \end{multicols} }
 }
\cs_new_protected:Npn \aksr_beginenum:n #1
 {
  \begin{enumerate}[#1]
 }
\cs_generate_variant:Nn \aksr_beginenum:n {V}

\tl_new:N \l__aksr_columns_tl
\tl_new:N \l__aksr_label_tl
\tl_new:N \l__aksr_enumitem_tl

\keys_define:nn { aksr/newenv }
 {
  columns .tl_set:N  = \l__aksr_columns_tl,
  columns .initial:n = 2,
  label   .tl_set:N  = \l__aksr_label_tl,
  label   .initial:n = \arabic*.,
  %% unknown keys will be passed to enumitem
  unknown .code:n    = \tl_put_right:Nx \l__aksr_enumitem_tl 
                        { 
                         \l_keys_key_tl % the key name
                         \tl_if_empty:nF { #1 } % the value, if not empty
                          { = \exp_not:n { #1 } } , },
 }
\ExplSyntaxOff

\begin{document}
\begin{newenv}
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[columns=1,noitemsep]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[label=\roman*)]
\item a
\item b
\item c
\item d
\end{newenv}

\hrule

\begin{newenv}[label=(\alph*),columns=3]
\item a
\item b
\item c
\item d
\item e
\item f
\end{newenv}

\end{document}

答案3

尽管这个建议可能会受到谴责,但你可以对不同的可选项使用不同的分隔符。

\NewDocumentEnvironment{newenv}{ O{2} D<>{(a)} }

指定有两个可选参数,第一个是O标准方括号可选类型,其默认值为以下括号组(此处2)中的内容。第二个可选参数是D(“D”限定)类型,其左分隔符<、右分隔符>为 ,默认值为以下括号组(此处 )中的内容(a)

\documentclass{article}
\usepackage{array}
\usepackage{multicol}
\usepackage{enumerate}
\usepackage{xparse}

\NewDocumentEnvironment{newenv}{ O{2} D<>{(a)} }
{\begin{multicols}{#1}\begin{enumerate}[#2]}
{\end{enumerate}\end{multicols}}

\begin{document}

\begin{newenv}[2]<i.>
  \item a
  \item b
  \item c
  \item d
\end{newenv}

\end{document}

相关内容