如何在列表出现在 .tex 文件之前引用列表中的项目数量?

如何在列表出现在 .tex 文件之前引用列表中的项目数量?

我希望 LaTeX “知道”某个列表中有多少项。我希望将这个数字存储在一个变量中。这样,我希望这个变量在第一次编译期间被采样,并可用于下一次编译。然后,我可以在同一文本中出现列表之前引用文本中的项目数。我该如何实现呢?我的最小示例不起作用。提前致谢 :)

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{etoolbox}

\begin{document}

%The following list contains \NumberOfItems\ items

\begin{enumerate} 

\item item A
\item item B
\item item C

\end{enumerate}
\newcommand{\NumberOfItems}{\value{enumi}}

The previous list contains \NumberOfItems\ items


\end{document}

答案1

如果您计划仅将其用于第一级列表,并且不打算使用该enumitem包来个性化环境,则\label在最后一项中使用就足够了。

然而,一个通用的解决方案是允许重新排列项目而不必担心的位置\label,也与 兼容,enumitem并且也适用于嵌套列表,可以是以下内容:

\documentclass[a4paper]{article}

\makeatletter
\newenvironment{enumeratecount}[1]
  {\def\thisenumeratecountlabel{#1}\enumerate}
  {\edef\@currentlabel{\number\value{\@enumctr}}%
   \label{\thisenumeratecountlabel}\endenumerate}
\makeatother

\begin{document}

The following list contains~\ref{firstlist} items, while
the nested list contains~\ref{innerlist}.

\begin{enumeratecount}{firstlist}
\item item A
\item item B
  \begin{enumeratecount}{innerlist}
  \item sub A
  \item sub B
  \end{enumeratecount}
\item item C
\end{enumeratecount}

The previous list contains \ref{firstlist} items, while the
inner list contains~\ref{innerlist}.

\end{document}

您只需\begin{enumeratecount}{<label>}声明要使用的标签(在环境之前或之后)即可获取项目数量。

如果你使用enumitem你甚至可以说

\begin{enumeratecount}{<label>}[<enumitem settings>]

例如,

\begin{enumeratecount}{mylist}[label=\Alph*]

可以正常工作(使用上面和 Ulrike 的回答中概述的“简单方法”则不行)。


该解决方案使用了几个事实:\label命令引用 的当前值\@currentlabel,因此在执行之前,\endenumerate我们将 定义\@currentlabel为 的完整扩展\value{\@enumctr}。宏\@enumctr扩展为enumienumiienumiiienumiv具体取决于当前环境的嵌套级别enumerate;因此我们保证在所有级别都获得正确的数字。然后我们说 会将\label{\thisenumeratecountlabel}标签名称设置为 的原始参数enumeratecount。环境的局部性完成其余工作。


扩展

假设我们要说“以下列表包含 1 个项目”或“以下列表包含 3 个项目”,有条件地添加“s”。

这可以借助该refcount包来完成。

\usepackage{refcount}
\newcommand{\addphrase}[3]{% #1 = label, #2 = text if number >1, #3 = text if number =1
  \ifnum\getrefnumber{#1}>1
    #2%
  \else
    #3%
  \fi}

因此上面的文本可以通过以下方式生成

the following list contains \ref{firstlist}~\addphrase{firstlist}{items}{item}

答案2

您的示例中已经\ref给出了正确的输出:

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{etoolbox}


\begin{document}

The following list contains \ref{a} items

\begin{enumerate} 

\item item A
\item item B
\item\label{a} item C

\end{enumerate}
\end{document}

答案3

问:我如何通过 Q:\newcommand 计算项目数量并将该数字存储在命令中?

A:为项目添加计数器

\let\olditem\item
\AtBeginEnvironment{enumerate}{
 \renewcommand{\item}{%
 \olditem%
 \stepcounter{mytempnumber}%
}}

一如既往,不能重新定义递归宏(这就是我们需要的原因\let)。我建议使用计数器来计数,而不是宏。

问:如何才能做到这一点,以便该变量的值能够延续到下一次编译中,并在下次编译时可用于“我的条件文本”?

A:写出来!你可以将其作为值,也可以作为赋值:

\AtEndDocument{%
 \openoutputfile{\jobname.num}{number}
 \addtostream{number}{%%
 \noexpand\setcounter{mynumber}{\themytempnumber}} 
 \closeoutputstream{number}
}

我们需要在这里小心处理扩展,因为写入文件时所有内容都会扩展。

完整代码如下:

\documentclass{article}
\usepackage{etoolbox}

\usepackage{newfile}

\newoutputstream{number}

\newcounter{mynumber}
\newcounter{mytempnumber}

\let\olditem\item
\AtBeginEnvironment{enumerate}{
 \renewcommand{\item}{%
 \olditem%
 \stepcounter{mytempnumber}%
}}

\AtEndDocument{%
\openoutputfile{\jobname.num}{number}
\addtostream{number}{%%
 \noexpand\setcounter{mynumber}{\themytempnumber}} 
\closeoutputstream{number}
}

\AtBeginDocument%
{%
\IfFileExists{\jobname.num}{\input{\jobname.num}}{\message{NO \jobname.num rerun!}}%
}

\begin{document}

\themynumber% use as normal counter

\begin{enumerate} 
\item Issue A
\item Issue B
\item Issue C
\item 
\end{enumerate}

\end{document}

我过去常常etoolbox挂接到enumerate环境中并newfile执行 i/o 操作,但这样更方便。感兴趣的用户会注意到,该文件<main file name>.num仅包含一行代码:\setcounter{mynumber}{4}。因此,在使用计数器之前包含该文件非常重要。

答案4

我使用了ifthen包而不是,etoolbox因为我更熟悉前者;后者可能有类似的构造。创建一个新的计数器,例如itemnum。在枚举命令的末尾设置计数器的值。然后使用一个小技巧:从计数器中取出 1,然后refstepcounter取它,这会将 1 加回并允许您将其值保存在标签中。该\ifthenelse命令使用它的值并将其与 1 进行比较。

当然,这需要运行 2 次才能生效,任何\label&\ref组合也是如此。

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{ifthen}

\newcounter{itemnum}

\begin{document}

This report will addresses the following 
\ifthenelse{\ref{label:itemnum}=1}{issue}{issues}.


\begin{enumerate} 

\item Issue A
\item Issue B
\item Issue C
\setcounter{itemnum}{\value{enumi}}
\addtocounter{itemnum}{-1}
\refstepcounter{itemnum}\label{label:itemnum}

\end{enumerate}



\end{document}

相关内容