关联计数器——同时步进(多个)计数器

关联计数器——同时步进(多个)计数器

这(也许)不是一个真正的问题,而且可能已经有对我的建议/请求的答案了。

情况

有些包提供了最后一页的编号(即lastpage或“较新”的pageslts包),第一个包不能保证它确实包含总页数,特别是在命令之后\pagenumbering{},第二个包提供了此功能(根据文档)

totcount对于计数器总值来说是一个非常有用的包,但是\chapters\appendix使用或类似命令时,无法重置或对计数器进行其他操作,尤其是对于页面等。

我认为,如果还有另一个与page(或chapter等)相关的计数器,比如totalpages(或totalchapters),当 发出 时也会自动增加\stepcounter{page},这样即使重置page计数器也不会对 产生任何影响,那就太好了totalpages。相关计数器最好\newtotcounters来自totcount包,但这不是强制性的。

可能存在编码情况,其中驱动计数器和相关计数器具有不同的值,但仍同时进行。

有一些相关问题,

我对此提出了一个主张,使用来自的列表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会导致偏差值。

是否有其他方法或包可以(更好地)处理计数器的同时步进?

我不认为aliascntH. 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/05assoccnt软件包已被取代,xassoccnt并可作为1.3CTAN 上的版本使用——该软件包比 更强大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}

驱动程序的输出与问题的快照基本相同。

笔记

  • 目前还没有测试这几个命令的参数是否完全是计数器(名称)
  • 没有测试可以证明两个(或更多)关联计数器不是相互关联的计数器。

我会不断提供更新和改进。

相关内容