提取部门单位的“父”计数器

提取部门单位的“父”计数器

我感兴趣的是查找特定部门单位的“父”计数器。例如,在以下文档结构中

1. A section
1.1 A subsection
1.1.1 A subsubsection
1.1.2 A subsubsection
1.1.2.1 A paragraph
1.2 A subsection
1.2.1 A subsubsection
1.2.1.1 A paragraph
1.2.1.2 A paragraph
1.2.2 A subsubsection

1.2.1 小节的(直接)“父级”是 1.2(小节)。1.1.2.1(段落)的(直接)“父级”是 1.1.2(小节)。

解决方案应该是

  • \parentlabel可以在某个部门单位内调用的形式;
  • 能够处理没有父级的部门单元。例如,如果部门单元是\chapter\thechapter定义为\arabic{chapter}\parentlabel则应为空{}(例如);并且
  • 足够灵活,以至于计数器显示的重新定义不起作用。也就是说,如果选择使用-而不是.,解决方案应该仍然有效。所以我不认为字符串解析(使用,比如,xstring) 将会很有用。

这是一次尝试和一个最小的游乐场:

在此处输入图片描述

\documentclass{article}
\def\parentlabel{\relax}% Placeholder for parent counter/level/label
\makeatletter
\let\oldsection\section
\renewcommand{\section}{\edef\parentlabel{\@currentlabel}\oldsection}%
\let\oldsubsection\subsection
\renewcommand{\subsection}{\edef\parentlabel{\@currentlabel}\oldsubsection}%
\let\oldsubsubsection\subsubsection
\renewcommand{\subsubsection}{\edef\parentlabel{\@currentlabel}\oldsubsubsection}%
\let\oldparagraph\paragraph
\renewcommand{\paragraph}{\edef\parentlabel{\@currentlabel}\oldparagraph}%
\newcommand{\showparent}{Current: \@currentlabel; Parent: \parentlabel}
\makeatother
\setcounter{secnumdepth}{4}
\begin{document}
\section{A section} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\paragraph{A paragraph} \showparent
\subsubsection{A subsubsection} \showparent
\end{document}

该方法依赖于\@currentlabel通过分段命令更新之前的捕获。

显然,这种方法在深入细分各个部分时效果很好。然而,回到更高的级别时,\parentlabel无法准确地表示“父”标签。

答案1

\documentclass{article}
\def\determinecurrentlevel{%
  \ifnum\value{section}=0
    0
  \else
    \ifnum\value{subsection}=0
      1
    \else
      \ifnum\value{subsubsection}=0
        2
      \else
        \ifnum\value{paragraph}=0
          3
        \else
          4
        \fi
      \fi
    \fi
  \fi
}
\def\showparent{%
  \ifcase\determinecurrentlevel
  \or
    \ifdefined\chapter\thechapter\fi
  \or
    \thesection
  \or
    \thesubsection
  \or
    \thesubsubsection
  \or
    \theparagraph
  \fi}

\setcounter{secnumdepth}{4}
\begin{document}
\section{A section} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\paragraph{A paragraph} \showparent
\subsubsection{A subsubsection} \showparent
\end{document}

可以使用以下方法减少较长的条件连接\numexpr

\def\determinecurrentlevel{%
  \numexpr
    \ifnum\value{section}>0       1+\fi
    \ifnum\value{subsection}>0    1+\fi
    \ifnum\value{subsubsection}>0 1+\fi
    \ifnum\value{paragraph}>0     1+\fi
  0\relax}

答案2

这是一个基于使用expl3数据类型的相当通用的解决方案prop。完整代码比其他解决方案略长。但是,它提供了一个完全通用的解决方案,可以开箱即用地与任意计数器组合配合使用。

主要思想是,在 LaTeX2e 中已经对此提供了很大一部分支持,因为计数器通常由其父计数器重置。因此,作为起点,我们假设此重置定义了父结构并添加代码以\@addtoreset存储父计数器。如果这还不够,我们提供\setparent手动指定父计数器。

我们需要的第二个组件是提供一个并行组件,我们将它添加到其中\@currentcounter。最后,我们提供一个计数器名称,用于排版(只需将其中一行放入单独的宏中即可)。\@currentlabel\refstepcounter\builtcurrentlabel\refstepcounter

\showparent然后只需排版当前标签和从父计数器生成的标签(如果有):

\makeatletter
\def\@addtoreset#1#2{%
   \expandafter\@cons\csname cl@#2\endcsname {{#1}}%
% NEW: store parent info
   \setparent {#1}{#2}%
}
\def\refstepcounter#1{\stepcounter{#1}%
    \protected@edef\@currentlabel
       {\csname p@#1\endcsname\csname the#1\endcsname}%
% NEW: save current counter
    \protected@edef\@currentcounter{#1}%
}
% NEW: taken from refstepcounter
\def\builtcurrentlabel #1{%
       \csname p@#1\endcsname
       \csname the#1\endcsname
}
\def\showparent{%
  Current: \@currentlabel; Parent: \typesetparentlabel{\@currentcounter}%
}
\makeatother

现在剩下要做的就是实际存储和检索父计数器映射。顺便说一下,所有这些都必须先发生,\documentclass以便计数器仍需定义,否则\@addtoreset将不起作用。所以我们必须使用\RequirePackage来加载 expl3。

我们将父计数器名称存储在属性列表 ( \g_pcnt_parent_counter_prop) 中,其中当前计数器名称作为键,父计数器作为值。这里唯一的额外复杂性是,将一个没有父计数器的新计数器添加到计数器中@ckpt(用于包含机制),我们不想将其视为父计数器:

\RequirePackage{expl3}

\ExplSyntaxOn

\prop_new:N \g_pcnt_parent_counter_prop 
\tl_new:N \l_pcnt_result_tl

\cs_new:Npn \pcnt_store_parent_counter:nn #1#2 {
   \str_if_eq:nnF{@ckpt}{#2}
       {  \prop_gput:Nnn \g_pcnt_parent_counter_prop {#1}{#2} }
}

检索同样简单:如果我们没有找到值,我们将返回一个空的标记列表

\cs_new:Npn \pcnt_get_parent_counter:nN #1#2 {
 \prop_get:NnN \g_pcnt_parent_counter_prop {#1} #2
  \quark_if_no_value:NT #2
    { \tl_clear:N #2 }
}
\cs_generate_variant:Nn \pcnt_get_parent_counter:nN {o} % needed below

最后的界面:排版父标签意味着检索父计数器名称,如果不为空则运行它\builtcurrentlabel

\cs_new_eq:NN \setparent \pcnt_store_parent_counter:nn

\cs_new:Npn \typesetparentlabel #1 {
  \pcnt_get_parent_counter:oN {#1} \l_pcnt_result_tl 
  \tl_if_empty:NF \l_pcnt_result_tl
     { \builtcurrentlabel{\l_pcnt_result_tl} }
}

如果我们愿意,我们还可以定义以下数据结构:

%% for tracing %%
\cs_new:Npn \showparentcounters {\prop_show:N \g_pcnt_parent_counter_prop }
\cs_new:Npn \showparentcounter #1 {
  \pcnt_get_parent_counter:nN {#1} \l_pcnt_result_tl 
  \tl_show:N  \l_pcnt_result_tl 
}

在问题的示例文档中将\showparentcounters产生

The property list \g_pcnt_parent_counter_prop contains the pairs (without
outer braces):
>  {subsection}  =>  {section}
>  {subsubsection}  =>  {subsection}
>  {paragraph}  =>  {subsubsection}
>  {subparagraph}  =>  {paragraph}.

答案3

一种灵活的方法是在每个分段命令中定义钩子来指示父计数器,而不必担心任何格式,这些格式将在相关\the命令中可用,例如\thesection。建议:

\@namedef{part}{}
\@namedef{parent@chapter}{\the\c@part}
\@namedef{parent@section}{\the\c@chapter}
\@namedef{parent@subsection}{\the\c@section}
\@namedef{parent@subsubsection}{\the\c@subsection}
\@namedef{parent@paragraph}{\the\c@subsubsection}

宏中存储的内容parent@section取决于您的需求。c@section如果您想在此之后进行任何详细操作,则可以仅存储部分。这只是创建指向父级的指针的一种方式。

我们还定义了两个方便测试的宏:

\def\sectionlist{part,chapter,section,subsection,
    subsubsection,paragraph}
\def\checkall{\@for\next:=\sectionlist\do{
      \next\ has parent = \csname parent@\next\endcsname\\
 }

完整极简图如下所示:

\documentclass{book}
\makeatletter
\makeatletter
\setcounter{secnumdepth}{6}
\def\sectionlist{part,chapter,section,subsection,
    subsubsection,paragraph}
\@namedef{part}{}
\@namedef{parent@chapter}{\the\c@part}
\@namedef{parent@section}{\the\c@chapter}
\@namedef{parent@subsection}{\the\c@section}
\@namedef{parent@subsubsection}{\the\c@subsection}
\@namedef{parent@paragraph}{\the\c@subsubsection}
\def\checkall{\@for\next:=\sectionlist\do{
 \next\ has parent = \csname parent@\next\endcsname\\
}
}
\makeatother
\begin{document}
\part{One}
\checkall
\chapter{One}
\checkall
\chapter{Two}
\checkall

\section{One}
\checkall
\subsection{One}
\checkall
\subsubsection{One}
\checkall
\paragraph{Test paragraph}
\checkall
\end{document}

相关内容