截断逐项列表

截断逐项列表

我想修改itemized环境(这里称为myitemized),以便它只显示第一个列表中的元素。基本上我希望能够做类似的事情

\documentclass{article}
\newcommand{\maxlist}{3}
\begin{document}
 \begin{myitemize}
  \item First item
  \item Second item
  \item Third item
  \item Fourth item
 \end{myitemize}
\end{document}

并得到

  • 第一项
  • 第二项
  • 第三项

其中,所有之后的项目\maxlist(本例中为 3)均被省略。

编辑 Niel de Beaudrap 的回答回答了上述问题。对于我的应用程序,我希望能够将截断环境包装在另一个环境中。类似于\newenvironment{wrapper}{\begin{truncitemize}}{\end{truncitemize}}

答案1

可以通过改编 中的部分代码来生成解决方案amsmath.sty。如果细节看起来很复杂,请不要担心,但这里有一些您可以使用的代码,并附有一些注释。

启用忽略列表中剩余项目的代码

我们需要某种方法来收集某个点之后项目列表中剩余的所有内容,其中项目要点也可能包含环境。这强烈促使我们使用与环境非常相似的代码来收集、和其他多行数学环境amsmath的主体。aligngather

编辑:正如评论中所述egreg,大多数功能由environ包提供,我们可能会将其包括在内以简化代码。但是,我们仍然需要修改环境\collect@body中使用的主宏的版本amsmath,以控制对已收集的列表项的实际操作。我们给它一个不同的名称,以便它不会与现有宏冲突,并对其进行了轻微的修改。具体来说,新宏不接受(或对)参数执行任何操作,并且不是实际使用它收集的源的内容,而是执行一个宏来代替列表中所有剩余的项目。(可以单独修改此宏以执行任何您喜欢的操作,包括什么都不做。)

\usepackage{environ}% <--- for \collect@@body, etc.

\makeatletter

\def\truncatedlist@omit{%
  \edef\process@envbody{%
    \noexpand\let\noexpand\item\noexpand\orig@item
    \noexpand\omitlistitems \noexpand\end{\@currenvir}}%
  \@envbody\@emptytoks \def\begin@stack{b}%
  \begingroup
  \expandafter\let\csname\@currenvir\endcsname\collect@@body
  \edef\process@envbody{\expandafter\noexpand\csname\@currenvir\endcsname}%
  \process@envbody
}

请特别注意第一行,它将 重新定义\item为某个宏 的值\orig@item。这是因为,对于您的截断列表环境,我们将修改 的定义\item,但在描述要做什么时,可能希望使用 的原始含义,\item而不是省略的项目。

定义新的截断列表环境

现在我们进入练习的重点。定义两个计数器:

\newcounter{trunclistnum}
\newcounter{trunclistlimit}
\setcounter{trunclistlimit}{3}% <--- or whatever limit you prefer

我们还定义了如何处理省略的项目。

\def\omitlistitems{\item $\cdots$}
% or if you prefer, \def\omitlistitems{}

最后,我们定义列表本身。以下代码基本上是itemize对 中的环境的修改latex.ltx。它将项目数设置为零,并重新定义\item以检查项目数是否超出限制。如果是,它会调用用于省略其余项目的宏;否则它会调用包含 的原始行为的宏\item

\let\endtruncitemize\enditemize
\def\truncitemize{%
  \ifnum \@itemdepth >\thr@@\@toodeep\else
    \c@trunclistnum=0\relax
    \let\orig@item\item
    \def\item{%
      \ifnum\c@trunclistnum<\c@trunclistlimit
        \let\@tempa\orig@item%
      \else
        \let\@tempa\truncatedlist@omit%
      \fi
      \advance\c@trunclistnum by 1%
      \@tempa}%
    \advance\@itemdepth\@ne
    \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}%
    \expandafter
    \list
      \csname\@itemitem\endcsname
      {\def\makelabel##1{\hss\llap{##1}}}%
  \fi}

\makeatother

示范

将所有这些内容放入文档的前言中,然后尝试以下内容:

\begin{document}

\subsection*{Result}
A truncated itemized list:
\begin{truncitemize}
\item First item
\item Second item
\item Third item
\item Fourth item
\item Yet further items  
\end{truncitemize}
A normal itemized list:
\begin{itemize}
\item First item
\item Second item
\item Third item
\item Fourth item
\item Yet further items  
\end{itemize}

\end{document}

示例代码的输出

答案2

我们可以让environ完成将环境内容加载到 中的大工作\BODY。然后我们重新定义\item一个计数器,在启动环境时将其设置为零itemize;然后 new\item检查计数器的值是否高于阈值(\maxlist)。在这种情况下,它会吞噬剩余的所有内容(可能会打印“省略”的项目);否则它会发出我们保留在 中的\ignore@to@end常规内容。\item\old@item

这甚至可以嵌套,并且可以使用可选参数在本地更改阈值。

\documentclass{article}
\usepackage{environ}

\makeatletter

\NewEnviron{myitemize}[1][\maxlist]{%
  \begin{itemize}
  \@tempcnta=\z@
  \def\item{\advance\@tempcnta\@ne\ifnum\@tempcnta>#1\relax
    \show@omitted@items
    \expandafter\ignore@to@end
      \else
    \expandafter\old@item
      \fi}%
  \BODY\final@sentinel
  \end{itemize}}

\long\def\ignore@to@end#1\final@sentinel{}%
\let\final@sentinel\@empty
\let\old@item\item

\newif\if@show@omitted
\newcommand{\showomitted}{\@show@omittedtrue}
\newcommand{\dontshowomitted}{\@show@omittedfalse}
\newcommand{\show@omitted@items}{\if@show@omitted\old@item\relax\dots\fi}
\makeatother

\newcommand{\maxlist}{3}

\begin{document}

\begin{myitemize}\showomitted
\item Yes
\item Yes
  \begin{myitemize}\dontshowomitted
\item Yes
\item Yes
\item Yes
\item No
\item No
\item No
\end{myitemize}
\item Yes
\item No
\item No
\item No
\end{myitemize}

separator

\begin{myitemize}[5]
\item Yes
\item Yes
\item Yes
\item No
\item No
\item No
\end{myitemize}

\end{document}

相关内容