如何使用 cleveref 显示父计数器的名称?

如何使用 cleveref 显示父计数器的名称?

考虑以下一段代码:

\documentclass{book}
\usepackage{cleveref}
\usepackage{lipsum}

\begin{document}
  \chapter{Chapter One}
  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}
  Please ignore \cref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \cref{mysection} is useless.
\end{document}

默认情况下,两种用法\cref均能获得Section 1.1预期的效果。

是否可以改变参考文献的显示方式,以便第二使用\cref上述方法将打印Section 1 of Chapter 1?即,也命名父计数器。

然而,这只能外部\cref自己的章节,因此上例中第一次使用时应该打印Section 1

这来自规范文本的用例,其中文档分为“文章”和“逗号”,并且最好有“文章 2 的逗号 1”或“文章 2,逗号 1”之类的引用。

答案1

更新于2017/03/05最后

更新 2017/06/07:类似问题https://tex.stackexchange.com/a/373769/31729

确定一个计数器的父计数器很容易,如果只有一个父计数器,那么这是一个唯一的映射。

我按顺序存储了文档开头定义的所有计数器,并“破解”了列表\cl@XX作为驱动程序计数器名称,例如chapter),将其内容存储到包含父计数器的属性列表中。

\getparentcounter宏可用于检索该值。

现在zref包存储了属性childcountervalueparentcountervalue以便parentcountername稍后使用 检索它们\zref@extract

锚点也被存储起来,以备我们使用hyperref

\parentcref\parentCref将输出父计数器和子计数器,其中第一个字符为小写(实际上是计数器名称),第一个字符为大写,即section → Section等等。

代码假设计数器仅使用数字,即\arabic{foo}。我将尝试消除此限制。

\documentclass{book}
\usepackage{etoolbox}
\usepackage{lipsum}
\usepackage{hyperref}
\usepackage[user,counter,hyperref]{zref}
\usepackage{cleveref}

\makeatletter
\AtEndPreamble{
\newif\if@hyperrefloaded

\@ifpackageloaded{hyperref}{%
  \@hyperrefloadedtrue
}{
  \@hyperrefloadedfalse
}
}
\makeatother

\usepackage{letltxmacro}



\usepackage{xparse}
\makeatletter

\ExplSyntaxOn
\prop_new:N \g_latex_parentcounters_prop 
\seq_new:N  \g_latex_counters_seq

\cs_generate_variant:Nn \seq_gset_from_clist:Nn {Nx,cx}
\cs_generate_variant:Nn \prop_item:Nn {Nx,cx,No}
\cs_generate_variant:Nn \str_head:n {x,o,V}
\cs_generate_variant:Nn \str_tail:n {x,o,V}
\cs_generate_variant:Nn \str_uppercase:n {x,o,V}
\cs_generate_variant:Nn \str_set:Nn {Nx,No}

% Store all reset lists and make a property list for each counter and its possible parent counter
\cs_new_nopar:Npn \GetAllResetLists {%
  \def\@elt##1{%
    \seq_gput_right:Nn \g_latex_counters_seq {##1}%
    \seq_new:c { g_latex_cntr_##1_seq }
  }
  \cl@@ckpt%
  \seq_map_inline:Nn \g_latex_counters_seq {%
    \def\@elt####1{####1,}
    \seq_gset_from_clist:cx { g_latex_cntr_##1_seq } { \use:c{cl@##1} }
  }
  % Now fill the parent counter lists
  \seq_map_inline:Nn \g_latex_counters_seq {%
    \seq_map_inline:cn { g_latex_cntr_##1_seq }{ %
      \prop_gput:Nnn \g_latex_parentcounters_prop {####1} {##1}
    }
  }
}

% Gives the parent counter of a specific counter (or nothing)
\cs_new:Npn \getparentcounter #1{%
  \prop_item:No \g_latex_parentcounters_prop {#1}
}

% Make the first character of a word upper case
\newcommand{\FirstUpcase}[1]{%
  \str_set:Nx \l_tmpa_str {#1}%
  \str_uppercase:x {\str_head:N \l_tmpa_str}\str_tail:V {\l_tmpa_str}%
}

\ExplSyntaxOff

\GetAllResetLists

\def\LastRefSteppedCounter{}

% Define new properties
\zref@newprop{childcountervalue}{\arabic{\LastRefSteppedCounter}}% This is the naked value
\zref@newprop{parentcountervalue}{\csname the\getparentcounter{\LastRefSteppedCounter}\endcsname}
\zref@newprop{parentcountername}{\getparentcounter{\LastRefSteppedCounter}}

% Add the new properties to the main property list stored with \zlabel
\zref@addprops{main}{childcountervalue,parentcountervalue,parentcountername}

\AtBeginDocument{%

  \LetLtxMacro\latex@@label\label
  \let\latex@@refstepcounterorig\refstepcounter

  \RenewDocumentCommand{\refstepcounter}{m}{%
    \global\xdef\LastRefSteppedCounter{#1}%
    \latex@@refstepcounterorig{#1}%
  }
  %Make the ordinary label and a \zlabel
  \RenewDocumentCommand{\label}{om}{%
    \IfValueTF{#1}{%
      \latex@@label[1]{#2}%
    }{%
      \latex@@label{#2}%
    }%
    \zlabel{#2}%
  }%
}

% Command for uppercase output
\NewDocumentCommand{\parentCref}{m}{%
  \zref@ifrefundefined{#1}{%
    \Cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \FirstUpcase{\zref@extract{#1}{counter}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \FirstUpcase{\zref@extract{#1}{counter}} \zref@extract{#1}{childcountervalue} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

% Command for lowercase output
\NewDocumentCommand{\parentcref}{m}{%
  \zref@ifrefundefined{#1}{%
    \cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \zref@extract{#1}{counter} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \zref@extract{#1}{parentcountername} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \zref@extract{#1}{counter} \zref@extract{#1}{childcountervalue} of \zref@extract{#1}{parentcountername} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}
\makeatother

\begin{document}
  \chapter{Chapter One}
  Please look at \parentCref{othersection} or at \parentCref{foosubsection} or at \parentcref{foosubsection}


  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}

  \subsection{A subsection} \label{foosubsection}
  Please ignore \parentCref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \parentCref{mysection} is useless.


  \chapter{Chapter Three}
  \section{Section Three.One}
  \section{Section Three.Two}\label{othersection}

\end{document}

在此处输入图片描述

对章节逐个部分进行重新编号,在章节编号的交叉引用中添加部分编号作为后缀对于类似的问题,但这不是重复的!

更新 2017/03/06此答案的某些功能已添加到xassoccntv1.3 包中(从下载关联直到它在 CTAN、TeXLive(自 2017/03/06 起)和 MikTeX 上可用)解决方案现在短得多:

\documentclass{book}
\usepackage{lipsum}
\usepackage{xassoccnt}
\usepackage{xpatch}
\usepackage{hyperref}
\usepackage[user,counter,hyperref]{zref}
\usepackage{cleveref}

\makeatletter
\AtEndPreamble{
  \newif\if@hyperrefloaded

\@ifpackageloaded{hyperref}{%
  \@hyperrefloadedtrue
}{
  \@hyperrefloadedfalse
}
}
\makeatother




\usepackage{xparse}
\makeatletter

\ExplSyntaxOn
\prop_new:N \g_latex_parentcounters_prop 
\seq_new:N  \g_latex_counters_seq

\cs_generate_variant:Nn \str_head:n {x,o,V}
\cs_generate_variant:Nn \str_tail:n {x,o,V}
\cs_generate_variant:Nn \str_uppercase:n {x,o,V}
\cs_generate_variant:Nn \str_set:Nn {Nx,No}

% Store all reset lists and make a property list for each counter and its possible parent counter

% Make the first character of a word upper case
\newcommand{\FirstUpcase}[1]{%
  \str_set:Nx \l_tmpa_str {#1}%
  \str_uppercase:x {\str_head:N \l_tmpa_str}\str_tail:V {\l_tmpa_str}%
}

\ExplSyntaxOff




% Define new properties
\zref@newprop{childcountervalue}{\arabic{\LastRefSteppedCounter}}% This is the naked value
\zref@newprop{parentcountervalue}{\csname the\GetParentCounter{\LastRefSteppedCounter}\endcsname}
\zref@newprop{parentcountername}{\GetParentCounter{\LastRefSteppedCounter}}

% Add the new properties to the main property list stored with \zlabel
\zref@addprops{main}{childcountervalue,parentcountervalue,parentcountername}

% Command for uppercase output
\NewDocumentCommand{\parentCref}{m}{%
  \zref@ifrefundefined{#1}{%
    \Cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \FirstUpcase{\zref@extract{#1}{counter}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \FirstUpcase{\zref@extract{#1}{counter}} \zref@extract{#1}{childcountervalue} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

% Command for lowercase output
\NewDocumentCommand{\parentcref}{m}{%
  \zref@ifrefundefined{#1}{%
    \cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \zref@extract{#1}{counter} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \zref@extract{#1}{parentcountername} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \zref@extract{#1}{counter} \zref@extract{#1}{childcountervalue} of \zref@extract{#1}{parentcountername} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

\makeatother


\GetAllResetLists
\RegisterPostLabelHook{\zlabel}



\begin{document}
\chapter{Chapter One}
  Please look at \parentCref{othersection} or at \parentCref{foosubsection} or at \parentcref{foosubsection}


  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}

  \subsection{A subsection} \label{foosubsection}
  Please ignore \parentCref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \parentCref{mysection} is useless.


  \chapter{Chapter Three}
  \section{Section Three.One}   %
  \section{Section Three.Two}\label{othersection}

\end{document}

相关内容