这(也许)不是一个真正的问题,而且可能已经有对我的建议/请求的答案了。
情况
有些包提供了最后一页的编号(即lastpage
或“较新”的pageslts
包),第一个包不能保证它确实包含总页数,特别是在命令之后\pagenumbering{}
,第二个包提供了此功能(根据文档)
totcount
对于计数器总值来说是一个非常有用的包,但是\chapters
当\appendix
使用或类似命令时,无法重置或对计数器进行其他操作,尤其是对于页面等。
我认为,如果还有另一个与page
(或chapter
等)相关的计数器,比如totalpages
(或totalchapters
),当 发出 时也会自动增加\stepcounter{page}
,这样即使重置page
计数器也不会对 产生任何影响,那就太好了totalpages
。相关计数器最好\newtotcounters
来自totcount
包,但这不是强制性的。
可能存在编码情况,其中驱动计数器和相关计数器具有不同的值,但仍同时进行。
有一些相关问题,
- 关于
\refstepcounter
重置,例如 柜台和他们的“伙伴” - 关于共享柜台(虽然我不确定这是否是我所说的同一个功能) 每页共享计数器
我对此提出了一个主张,使用来自的列表etoolbox
和重新定义的\stepcounter
命令,该命令贯穿整个列表并执行相关的计数器。
\documentclass{book}%
\usepackage{etoolbox}%
\usepackage{totcount}%
% Some packages only for output and dummy pages
\usepackage{blindtext}%
\usepackage{forloop}%
\usepackage{xcolor}%
\newcounter{loopcounter}%
\makeatletter
\let\LaTeXStandardStepCounter\stepcounter%
% This command defines a list for
\newcommand{\DeclareAssociatedCounters}[2]{%
% #1 --> driver counter
% #2 --> CSV list of other counters, that should be stepped, if the driver counter is stepped
%
\csgdef{@#1AssociatedList}{}% Define some global list
\forcsvlist{\listcsadd{@#1AssociatedList}}{#2}%
}%
\newcommand{\stepassociatedcounter}[1]{% A wrapper, if the list command has to be extended later on
\LaTeXStandardStepCounter{#1}%
}%
\renewcommand{\stepcounter}[1]{%
\LaTeXStandardStepCounter{#1}% Traditional behaviour, since this is expected!
\ifcsdef{@#1AssociatedList}{% Check first, whether the list exists at all,
\forlistcsloop{\stepassociatedcounter}{@#1AssociatedList}% March through the list
}{% No list -> do nothing at all
}%
}%
\makeatother
\newcommand{\ShowNiceCounterOutput}[5]{%
\begin{center}%
\begin{tabular}{llll}%
& & & \tabularnewline
& \multicolumn{3}{c}{totcount page values} \tabularnewline
Page & \textcolor{red}{#1} & \textcolor{blue}{#2} & \textcolor{gray}{#3} \tabularnewline
\thepage & \textcolor{red}{\number\totvalue{#1}} & \textcolor{blue}{\number\totvalue{#2}} & \textcolor{gray}{\number\totvalue{#3}} \tabularnewline
& & & \tabularnewline
& \multicolumn{3}{c}{totcount section values} \tabularnewline
Section & \textcolor{red}{#4} & \textcolor{blue}{#5} \tabularnewline
\thesection & \textcolor{red}{\number\totvalue{#4}} & \textcolor{blue}{\number\totvalue{#5}} & \tabularnewline
& & & \tabularnewline
\end{tabular}
\end{center}%
}%
\begin{document}
\regtotcounter{page} % Register a total value counter --> this will be the driver counter
\newtotcounter{totalpages}% 1st driven counter
\newtotcounter{anotherpagescounter}% 2nd driven counter
\regtotcounter{section}%
\newtotcounter{totalsections}
\DeclareAssociatedCounters{page}{totalpages,anotherpagescounter}% Register the driver and the driven counters
\DeclareAssociatedCounters{section}{totalsections}% Register the driver and the driven counters for sections%
\pagenumbering{Roman}%
\chapter{The first chapter}%
\section{My first section}%
% Generate dummy output
\forloop{loopcounter}{1}{\value{loopcounter} < 11}{%
\ShowNiceCounterOutput{page}{totalpages}{anotherpagescounter}{section}{totalsections}%
\blindtext%
\newpage% 10 pages!
}%
\section{My second section}%
% Generate dummy output, again ;-)
\forloop{loopcounter}{1}{\value{loopcounter} < 11}{%
\pagenumbering{arabic}% -> pagenumber reset to zero , on purpose inside the loop
\ShowNiceCounterOutput{page}{totalpages}{anotherpagescounter}{section}{totalsections}%
\blindtext%
\newpage% 10 pages!
}%
\pagenumbering{arabic}% -> pagenumber reset to zero
\appendix
\chapter{First Appendix chapter}%
\section{My (only) appendix section}%
% Generate dummy output, again ;-)
\forloop{loopcounter}{1}{\value{loopcounter} < 11}{%
\ShowNiceCounterOutput{page}{totalpages}{anotherpagescounter}{section}{totalsections}%
\blindtext%
\newpage% 10 pages!
}%
\end{document}
MWE 多次重置页码,以及部分计数\chapters
等。该命令提供了与驱动程序计数器“绑定”的计数器列表。屏幕截图显示,即使重置驱动程序计数器也不会影响相关计数器的总值。在示例中,按设置有 30 页和 3 个部分,这些数字由应用于相关计数器的命令\DeclareAssociateCounters
报告。\totvalue
当然,对驱动程序或相关计数器值的操纵\setcounter
当然\addtocounter
会导致偏差值。
是否有其他方法或包可以(更好地)处理计数器的同时步进?
我不认为aliascnt
H. Oberdiek 提出的那个包解决了同样的问题。
答案1
为了完整性,下面是使用以下实现expl3
:
\documentclass{book}
\usepackage{xparse}
\usepackage{blindtext}
\usepackage{xcolor}
\usepackage{totcount}
\ExplSyntaxOn
\NewDocumentCommand{\DeclareAssociatedCounters}{mm}
{
\hupfer_declareassociatedcounters:nn { #1 } { #2 }
}
\NewDocumentCommand{\AddAssociatedCounters}{mm}
{
\hupfer_addassociatedcounters:nn { #1 } { #2 }
}
\NewDocumentCommand{\RemoveAssociatedCounters}{mm}
{
\hupfer_removeassociatedcounters:nn { #1 } { #2 }
}
\NewDocumentCommand{\ClearAssociatedCountersList}{m}
{
\hupfer_declareassociatedcounters:nn { #1 } { }
}
\cs_new_protected:Nn \hupfer_declareassociatedcounters:nn
{
\clist_clear_new:c { g_hupfer_bound_counters_#1_clist }
\hupfer_addassociatedcounters:nn { #1 } { #2 }
}
\cs_new_protected:Nn \hupfer_addassociatedcounters:nn
{
\clist_gput_right:cn { g_hupfer_bound_counters_#1_clist } { #2 }
% or a slower routine if we want to check the items are counter names
%\clist_map_inline:nn { #2 }
% {
% \cs_if_exist:cTF { c@##1 }
% {
% \clist_gput_right:cn { g_hupfer_bound_counters_#1_clist } { ##1 }
% }
% {
% \ERROR{NOT A COUNTER}
% }
% }
%%%%
\clist_gremove_duplicates:c { g_hupfer_bound_counters_#1_clist }
% remove accidental #1 from the list
\clist_gremove_all:cn { g_hupfer_bound_counters_#1_clist } { #1 }
}
\cs_new_protected:Nn \hupfer_removeassociatedcounters:nn
{
\clist_map_inline:nn { #2 }
{
\clist_gremove_all:cn { g_hupfer_bound_counters_#1_clist } { ##1 }
}
}
\cs_new_protected:Npn \hupfer_stepcounter:n #1
{
\hupfer_orig_stepcounter:n { #1 }
\clist_if_exist:cT { g_hupfer_bound_counters_#1_clist }
{
\clist_map_inline:cn { g_hupfer_bound_counters_#1_clist }
{
\hupfer_orig_stepcounter:n { ##1 }
}
}
}
\AtBeginDocument
{
% save a copy of \stepcounter
\cs_set_eq:NN \hupfer_orig_stepcounter:n \stepcounter
% use the new one
\cs_set_eq:NN \stepcounter \hupfer_stepcounter:n
}
\ExplSyntaxOff
\newcommand{\ShowNiceCounterOutput}[5]{%
\begin{center}
\begin{tabular}{llll}
& & & \\
& \multicolumn{3}{c}{totcount page values} \\
Page & \textcolor{red}{#1} & \textcolor{blue}{#2} & \textcolor{gray}{#3} \\
\thepage & \textcolor{red}{\number\totvalue{#1}} &
\textcolor{blue}{\number\totvalue{#2}} & \textcolor{gray}{\number\totvalue{#3}} \\
& & & \\
& \multicolumn{3}{c}{totcount section values} \\
Section & \textcolor{red}{#4} & \textcolor{blue}{#5} \\
\thesection & \textcolor{red}{\number\totvalue{#4}} &
\textcolor{blue}{\number\totvalue{#5}} & \\
& & & \\
\end{tabular}
\end{center}%
}
\ExplSyntaxOn
\NewDocumentCommand{\QuickOutput}{m}
{
\prg_replicate:nn { #1 }
{
\pagenumbering{arabic}% -> pagenumber reset to zero , on purpose inside the loop
\ShowNiceCounterOutput{page}{totalpages}{anotherpagescounter}{section}{totalsections}
\blindtext
\newpage% some pages
}
}
\ExplSyntaxOff
\begin{document}
\regtotcounter{page} % Register a total value counter --> this will be the driver counter
\newtotcounter{totalpages}% 1st driven counter
\newtotcounter{anotherpagescounter}% 2nd driven counter
\newtotcounter{yetanotherpagescounter}% 3rd driven counter
\regtotcounter{section}
\newtotcounter{totalsections}
\DeclareAssociatedCounters{page}{totalpages,anotherpagescounter}% Register the driver and the driven counters
\DeclareAssociatedCounters{section}{section,totalsections}% Register the driver and the driven counters for sections%
\AddAssociatedCounters{page}{yetanotherpagescounter}% Register the driver and the driven counters
\pagenumbering{Roman}
\chapter{The first chapter}
\section{My first section}
% Generate dummy output
\QuickOutput{10}
\section{My second section}
\QuickOutput{10}
\pagenumbering{arabic}% -> pagenumber reset to zero
\appendix
\chapter{First Appendix chapter}
\section{My (only) appendix section}
% Generate dummy output, again ;-)
\QuickOutput{10}
% Clear the list of counters associated to page
\ClearAssociatedCountersList{page}
% Not necessary, only for removing some counters from list
\RemoveAssociatedCounters{page}{totalpages,anotherpagescounter}
% Readd the counter totalpages to the list --> in this context,
% It acts, as if it has not been removed at all
\DeclareAssociatedCounters{page}{totalpages}
\QuickOutput{20}
\end{document}
答案2
更新 2017/03/05该assoccnt
软件包已被取代,xassoccnt
并可作为1.3
CTAN 上的版本使用——该软件包比 更强大assoccnt
——请不要assoccnt
再使用并切换到xassoccnt
。
正如 egreg 所说:LaTeX 内核不提供这样的功能,也许有其他软件包具有此功能,所以我决定提供一个小包,上传到 CTAN 并可能很快就会推出。
文件assoccnt.sty
\NeedsTeXFormat{LaTeX2e}%
\ProvidesPackage{assoccnt}[2014/08/13 v0.2 -- Associate counters stepping]%
%%%
%% License: LaTeX Project Public License
%% Copyright (2014) Dr. Christian Hupfer
%% Author: Christian Hupfer [email protected]
%%
%%
%%%%
%%% Some options later on
%%%%
\RequirePackage{etoolbox}[2011/01/03 2.2]%
\let\@@assoccnt@standardstepcounter\stepcounter%
\let\@@assoccnt@standardrefstepcounter\refstepcounter%
% Just for a quick suffix
\newcommand{\@@associatedcounterslistsuffix}{%
AssociatedCountersList%
}%
%%% Internal macro to generate the name of the list of associated counters
\newcommand{\@@assoccnt@@generatelistname}[1]{%
% #1 Name of the driver counter
@#1\@@associatedcounterslistsuffix
}%
\newcommand{\@@assoccnt@@addassociatedcounter}[2]{%
\ifcsdef{#1}{%
\ifinlistcs{#2}{#1}{%
% Do nothing, since counter is already in the list
}{%
\listcsadd{#1}{#2}%
}%
}{%
% Nothing in here
}%
}%
% This command defines a list of counters, that should be stepped also if the driver counter
% is `\stepcounter`ed.
% A self - association is not possible, as this would lead to inconsistent counting
\newcommand{\DeclareAssociatedCounters}[2]{%
% #1 --> driver counter
% #2 --> CSV list of other counters, that should be stepped, if the driver counter is stepped
\ifcsdef{\@@assoccnt@@generatelistname{#1}}{%
% % Nothing to be done --> List already exists
\GenericWarning{}{Warning: List of associated counters for counter #1 already exists}%
}{%
\csgdef{\@@assoccnt@@generatelistname{#1}}{}% Define some global list
}%
% Now add the counter names from #2 to the list
% Note: Currently, it is not checked whether a counter is already added!
\forcsvlist{\@@assoccnt@@addassociatedcounter{\@@assoccnt@@generatelistname{#1}}}{#2}%
% Now remove an accidental self-association
\RemoveAssociatedCounter{#1}{#1}%
}%
%%% A generic macro, that removes a list entry from the list by
%%% defining a temporary list and omitting the
\newcommand{\@@assoccnt@removefromlist}[2]{%
% #1 list name
% #2 element to be removed
\ifcsdef{#1}{%
\gdef\@@mytemplist{}%
\renewcommand*{\do}[1]{%
\ifstrequal{##1}{#2}{
% Later one some success routine etc. ???
}{%
\listgadd{\@@mytemplist}{##1}%
}%
}%
\dolistcsloop{#1}%
\csxdef{#1}{\@@mytemplist}%
}{%
% The list is not defined at all, can't remove something from something not existing...
}%
}%
%% Remove a particular counter from the list
\newcommand{\RemoveAssociatedCounter}[2]{%
% #1 arg: driver counter
% #2 arg: counter name to be removed
\@@assoccnt@removefromlist{\@@assoccnt@@generatelistname{#1}}{#2}%
}%
%% Remove a CSV list of counters from the list of associated counters
\newcommand{\RemoveAssociatedCounters}[2]{%
% #1 arg: driver counter
% #2 arg: CSV list of counters to be removed
\forcsvlist{\RemoveAssociatedCounter{#1}}{#2}%
}%
%% Remove all associated counters from the list
\newcommand{\ClearAssociatedCountersList}[1]{%
% #1 arg: driver counter
\csundef{\@@assoccnt@@generatelistname{#1}}%
}%
%% Test if a counter is an associated counter of driver counter
\newcommand{\IfIsAssociatedCounter}[4]{%
% #1 arg: driver counter
% #2 arg: (possibly) associated counter
% #3 arg: Code for execution on true branch
% #4 arg: Code for execution on false branch
\ifcsdef{\@@assoccnt@@generatelistname{#1}}{%
\ifinlistcs{#2}{\@@assoccnt@@generatelistname{#1}}{%
#3%
}{%
#4%
}%
}{% List does not exist, so it's not associated
#4%
}%
}%
%%% The stepcounter wrapper for the standard stepcounter command
%%% This is just for convenience, if the command as to be improved/extended later on in future
\newcommand{\@@assoccnt@stepcounter}[1]{%
\@@assoccnt@standardstepcounter{#1}%
}%
%%% Not needed so far
\newcommand{\@@assoccnt@refstepcounter}[1]{%
\@@assoccnt@standardrefstepcounter{#1}%
}%
%%%% Redefinition of the \stepcounter command
\renewcommand{\stepcounter}[1]{%
\@@assoccnt@standardstepcounter{#1}% Traditional behaviour, since this is expected!
\ifcsdef{\@@assoccnt@@generatelistname{#1}}{% Check first, whether the list exists at all,
\forlistcsloop{\@@assoccnt@stepcounter}{\@@assoccnt@@generatelistname{#1}}% March through the list
}{%
%No list -> do nothing at all
}%
}%
%%%% Redefinition of the \stepcounter command
\renewcommand{\refstepcounter}[1]{%
\@@assoccnt@standardstepcounter{#1}% Traditional behaviour, since this is expected!
\protected@edef\@currentlabel%
{\csname p@#1\endcsname\csname the#1\endcsname}%
\ifcsdef{\@@assoccnt@@generatelistname{#1}}{% Check first, whether the list exists at all,
\forlistcsloop{\@@assoccnt@stepcounter}{\@@assoccnt@@generatelistname{#1}}% March through the list
}{%
%No list -> do nothing at all
}%
}%
\endinput%
还有一些测试驱动文件
\documentclass{book}%
\usepackage{totcount}%
\usepackage{assoccnt}%
% Some packages only for output and dummy pages
\usepackage{blindtext}%
\usepackage{forloop}%
\usepackage{xcolor}%
\newcounter{loopcounter}%
\newcommand{\ShowNiceCounterOutput}[5]{%
\begin{center}%
\begin{tabular}{llll}%
& & & \tabularnewline
& \multicolumn{3}{c}{totcount page values} \tabularnewline
Page & \textcolor{red}{#1} & \textcolor{blue}{#2} & \textcolor{gray}{#3} \tabularnewline
\thepage & \textcolor{red}{\number\totvalue{#1}} & \textcolor{blue}{\number\totvalue{#2}} & \textcolor{gray}{\number\totvalue{#3}} \tabularnewline
& & & \tabularnewline
& \multicolumn{3}{c}{totcount section values} \tabularnewline
Section & \textcolor{red}{#4} & \textcolor{blue}{#5} \tabularnewline
\thesection & \textcolor{red}{\number\totvalue{#4}} & \textcolor{blue}{\number\totvalue{#5}} & \tabularnewline
& & & \tabularnewline
\end{tabular}
\end{center}%
}%
\newcommand{\QuickOutput}[1]{%
%
\forloop{loopcounter}{1}{\value{loopcounter} < \numexpr #1+1}{%
\pagenumbering{arabic}% -> pagenumber reset to zero , on purpose inside the loop
\ShowNiceCounterOutput{page}{totalpages}{anotherpagescounter}{section}{totalsections}%
\blindtext%
\newpage% some pages
}%
}%
\begin{document}
\regtotcounter{page} % Register a total value counter --> this will be the driver counter
\newtotcounter{totalpages}% 1st driven counter
\newtotcounter{anotherpagescounter}% 2nd driven counter
\newtotcounter{yetanotherpagescounter}% 3rd driven counter
\regtotcounter{section}%
\newtotcounter{totalsections}
\DeclareAssociatedCounters{page}{totalpages,anotherpagescounter}% Register the driver and the driven counters
\DeclareAssociatedCounters{section}{section,totalsections}% Register the driver and the driven counters for sections%
\DeclareAssociatedCounters{page}{yetanotherpagescounter}% Register the driver and the driven counters
\pagenumbering{Roman}%
\chapter{The first chapter}%
\section{My first section}%
% Generate dummy output
\QuickOutput{10}%
\section{My second section}%
\QuickOutput{10}%
\pagenumbering{arabic}% -> pagenumber reset to zero
\appendix
\chapter{First Appendix chapter}%
\section{My (only) appendix section}%
% Generate dummy output, again ;-)
\QuickOutput{10}%
% Clear the list of counters associated to page
\ClearAssociatedCountersList{page}%
% Not necessary, only for removing some counters from list
\RemoveAssociatedCounters{page}{totalpages,anotherpagescounter}%
% Readd the counter totalpages to the list --> in this context,
% It acts, as if it has not been removed at all
\DeclareAssociatedCounters{page}{totalpages}
\QuickOutput{20}%
\end{document}
驱动程序的输出与问题的快照基本相同。
笔记
- 目前还没有测试这几个命令的参数是否完全是计数器(名称)
- 没有测试可以证明两个(或更多)关联计数器不是相互关联的计数器。
我会不断提供更新和改进。