![如何使用 cleveref 显示父计数器的名称?](https://linux22.com/image/349398/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20cleveref%20%E6%98%BE%E7%A4%BA%E7%88%B6%E8%AE%A1%E6%95%B0%E5%99%A8%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%9F.png)
考虑以下一段代码:
\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@X
(X
作为驱动程序计数器名称,例如chapter
),将其内容存储到包含父计数器的属性列表中。
该\getparentcounter
宏可用于检索该值。
现在zref
包存储了属性childcountervalue
,parentcountervalue
以便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此答案的某些功能已添加到xassoccnt
v1.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}