![如何在列表出现在 .tex 文件之前引用列表中的项目数量?](https://linux22.com/image/262620/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%88%97%E8%A1%A8%E5%87%BA%E7%8E%B0%E5%9C%A8%20.tex%20%E6%96%87%E4%BB%B6%E4%B9%8B%E5%89%8D%E5%BC%95%E7%94%A8%E5%88%97%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%A1%B9%E7%9B%AE%E6%95%B0%E9%87%8F%EF%BC%9F.png)
我希望 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
扩展为enumi
、enumii
或enumiii
,enumiv
具体取决于当前环境的嵌套级别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}