![我怎样才能让 cleveref 压缩对同一部分的多个引用?](https://linux22.com/image/324052/%E6%88%91%E6%80%8E%E6%A0%B7%E6%89%8D%E8%83%BD%E8%AE%A9%20cleveref%20%E5%8E%8B%E7%BC%A9%E5%AF%B9%E5%90%8C%E4%B8%80%E9%83%A8%E5%88%86%E7%9A%84%E5%A4%9A%E4%B8%AA%E5%BC%95%E7%94%A8%EF%BC%9F.png)
编辑cleveref
:该问题已在0.21版本中得到解决。
我希望能够像cleveref
压缩对同一页面的多个引用一样压缩对同一部分的多个引用。唉,我不知道该怎么做。
最小工作示例结果
表达式和定义出现在第 1 页的 1.1 和 1.1 节中。
但我所希望的是
表达式和定义出现在第 1 页第 1.1 节中。
关键是我不想知道这两个标签是否在同一个部分或在不同的部分。 我希望 cleveref 能帮我跟踪这些。我的真实文档包含大量这样的对(几十个),手动检查部分并不吸引人——它们可能会发生变化。
我怎样才能让 cleveref 将对第 1.1 节的两个引用压缩为一个引用?
\documentclass{book}
\usepackage{cleveref}
\begin{document}
\chapter{This chapter}
\section{A section}
Expressions\label{exp.int}
Definitions\label{def.int}
\section{Another section}
Expressions and definitions occur in
\cref{exp.int,def.int} on
\cpageref{exp.int,def.int}.
\end{document}
答案1
假设我理解您的方法,这里有一个包装器,\cref
它根据“类型”(即它们引用的计数器)和“标签”(即标签的计数器值)删除重复的标签。如果列表中的多个标签引用相同的“类型”和“标签”组合,则只保留第一个。
胆量:
\forcsvlist
使用from解析逗号分隔的列表。使用和frometoolbox
检索每个条目的“类型”和“标签” 。使用唯一全局命令(由“类型”和“标签”组成)来指示该组合是否曾经使用过。如果未定义唯一命令或它等于,则将唯一命令重新定义为等于标签,并将标签附加到包含压缩列表的位置。如果存在唯一命令并且它不等于,则跳过标签并发出警告(如果您愿意,可以将其注释掉)。\cref@gettype
\cref@getlabel
cleveref
\relax
\compressed@list
\relax
然后将压缩列表传递给 的旧版本\cref
。最后,将每个唯一命令重新初始化为 ,\relax
以\forcsvlist\@clear@list{\compressed@list}
准备后续\cref
调用。\DeclareRobustCommand
用于保留\cref
标题中的 的本机功能。
编辑:正如OP在下面的评论中指出的那样,这个答案的原始版本没有将未定义的标签传递给\cref
;此版本已被更正。
\documentclass{book}
\usepackage{cleveref}
%%pre-compress labels to remove duplicates
\usepackage{etoolbox}
\makeatletter
%Robust, allowing \cref to be used in headings (may or may not be desired)
\DeclareRobustCommand\@create@list[1]{%
\ifcsname r@#1@cref\endcsname%only process if the label is defined
\cref@gettype{#1}{\@temptype}%cleveref command, set \@temptype to type associated with label (i.e., the counter name)
\cref@getlabel{#1}{\@templbl}%cleveref command, set \@templbl to the label (i.e., number) associated with the label
\ifcsname Addval\@temptype\@templbl\endcsname%already defined
\expandafter\if\csname Addval\@temptype\@templbl\endcsname\relax%equal to relax
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\else%already defined and not equal to \relax
\@latex@warning{Label #1 is a duplicate of \@temptype\space\@templbl}%
\fi
\else%not defined yet
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\fi
\else%Added in edit: label not defined...add to the list anyway for "standard" handling
\if\compressed@list\relax%
\gdef\compressed@list{#1}\else
\g@addto@macro\compressed@list{,#1}\fi
\fi}
%Robust, allowing \cref to be used in headings (may or may not be desired)
\DeclareRobustCommand\@clear@list[1]{%command to set the addval\@temptype\@templbl commands to relax
\ifcsname r@#1@cref\endcsname%only process if the label is defined
\cref@gettype{#1}{\@temptype}%cleveref command, set \@temptype to type associated with label (i.e., the counter name)
\cref@getlabel{#1}{\@templbl}%cleveref command, set \@templbl to the label (i.e., number) associated with the label
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{\relax}\fi}
\def\compressed@list{\relax}%initialize
\let\old@cref=\cref
\def\cref#1{%Now, cref will compress duplicate labels and provide a warning if found
\gdef\compressed@list{\relax}%ensure \relax
\expandafter\forcsvlist\expandafter\@create@list\expandafter{#1}%create compressed list
\if\relax\compressed@list\relax\else
\old@cref{\compressed@list}%pass compresed list to cref
\expandafter\forcsvlist\expandafter\@clear@list\expandafter{\compressed@list}%clear compressed list
\fi}
\makeatother
\begin{document}
\chapter{This chapter}
\section{A section}
Expressions\label{exp.int}
Definitions\label{def.int}
\section{Another section}
Expressions and definitions occur in
\cref{exp.int,def.int} on
\cpageref{exp.int,def.int}.
\end{document}
答案2
我看不出有什么理由不是压缩对同一标签的多个引用(就像cleveref
对页面引用所做的那样)。“第 1 和 1 节”肯定不是我们想要的。
因此,我在的最新预发布版本 (0.21) 中实现了此功能cleveref
,可从我的网站获取:http://www.dr-qubit.org/latex.html
现在它应该可以做你想做的事了。
答案3
我怀疑你是否能按照原作者的做法来做。看来作者的意图是能够引用章节和页码,为此,对标签的位置进行一些思考和规划会有所帮助。
理想情况下,你应该将标签放在你想要引用的部分或段落后面。所以它看起来应该是这样的:
\documentclass{book}
\usepackage{cleveref}
\begin{document}
\chapter{This chapter}
\section{A section}
\label{sec:section}
Expressions\label{exp.int}
Definitions\label{def.int}
\section{Another section}
这应该能标记出各个部分和相关段落。现在我们需要考虑一下我们在写文本时指的是什么
Expressions and definitions occur in \cref{sec:section} on \cpageref{exp.int,def.int}.
\end{document}
这里我们在正确的区域对节和段落进行了具体的引用。由于段落的页面相同,cleveref 将对其进行压缩。
希望有所帮助。
答案4
我必须解决 guho 答案中的几个错误。它需要\Cref
以及\Cref
,此外还有一些未定义事物的棘手问题:
未定义的标签应该被传递,而不是被忽略,以便用户可以收到错误消息。
对于看起来像的标签也是如此
\relax
。\@clear@list{\compressed@list}
需要一些\expandafter
s(或者可以直接经过#1
那里。
我把整个东西都变成了包装cleveref
。我是个业余爱好者,所以可能有些东西很奇怪或错误。
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{cleveref-nodups}[2015/12/06]
% eliminate duplicate refs in cleveref
% http://tex.stackexchange.com/posts/281611/edit
%
% Thanks http://tex.stackexchange.com/users/89497/guho
\newif\ifwarn@compress
\warn@compressfalse
\DeclareOption{warncompress}{\warn@compresstrue}
\DeclareOption{nowarncompress}{\warn@compressfalse}
\DeclareOption*{%
% \edef\@tempa{warncompress}%
% \ifx\@tempa\CurrentOption
% % do nothing
% \else
% \edef\@tempa{nowarncompress}%
% \ifx\@tempa\CurrentOption
% % do nothing
% \else
\PassOptionsToPackage{\CurrentOption}{cleveref}%
% \fi
% \fi
}
\ProcessOptions
\RequirePackage{cleveref}
\RequirePackage{etoolbox}
\RequirePackage{xstring}
%
%
% Assuming I understand your approach, here is a wrapper for `\cref`
% which removes duplicate labels on the basis of the "type" (i.e., the
% counter to which they refer) and the "label" (i.e., the value of the
% counter for the label). If multiple labels in a list refer to the same
% "type" and "label" combination, only the first is retained.
%
% **The guts:**
%
% The overloaded `\cref` first checks if a comma is contained in the
% argument. If so, the comma separated list is parsed with `\forcsvlist`
% from `etoolbox`. The "type" and "label" for each entry are retrieved
% using the `\cref@gettype` and `\cref@getlabel` from `cleveref`. A
% unique global command (comprised of the "type" and "label") is used to
% indicate if the combination has been used before. If the unique
% command is not defined or it is equal to `\relax`, then the unique
% command is redefined to be equal to the label and the label is
% appended to `\compressed@list` which contains the compressed list. If
% the unique command exists and it is not equal to `\relax`, the label
% is skipped and a warning is raised (this may be commented out if you
% so desire).
%
% The compressed list is then passed to the old version of
% `\cref`. Finally, each of the unique commands are reinitialized to
% `\relax` with `\forcsvlist\@clear@list{\compressed@list}` in
% preparation for subsequent `\cref` calls. `\DeclareRobustCommand` and
% `\protect\IfSubStr` were used to retain the native functionality of
% `\cref` in headings.
%Robust, allowing \cref to be used in headings (may or may not be desired)
\def\addto@compressed@list#1{%
\if\compressed@list\relax%
\gdef\compressed@list{#1}%
\else
\g@addto@macro\compressed@list{,#1}%
\fi
}
\DeclareRobustCommand\@create@list[1]{%
\ifcsname r@#1@cref\endcsname %only process if the label is defined
\expandafter\if\csname r@#1@cref\endcsname\relax
\addto@compressed@list{#1}%
\else
\cref@gettype{#1}{\@temptype}% \@temptype := type of label (e.g., section)
\cref@getlabel{#1}{\@templbl}% \@templbl := label (e.g., 2.5)
\ifcsname Addval\@temptype\@templbl\endcsname %already defined
\expandafter\if\csname Addval\@temptype\@templbl\endcsname\relax%equal to relax
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\addto@compressed@list{#1}%
\else % already defined and not equal to \relax
\ifwarn@compress
\@latex@warning{Label #1 is a duplicate of \@temptype\space\@templbl}%
\fi
\fi
\else %not defined yet
\expandafter\gdef\csname Addval\@temptype\@templbl\endcsname{#1}%save the label
\addto@compressed@list{#1}%
\fi
\fi
\else
\addto@compressed@list{#1}%
\fi}
%Robust, allowing \cref to be used in headings (may or may not be desired)
\DeclareRobustCommand\@clear@list[1]{%
% sets the addval\@temptype\@templbl commands to relax
\ifcsname r@#1@cref\endcsname %only process if the label is defined
\cref@gettype{#1}{\@temptype}% \@temptype := type of label (e.g., section)
\cref@getlabel{#1}{\@templbl}% \@templbl := label (e.g., 2.5)
\expandafter\gdef\csname
Addval\@temptype\@templbl\endcsname{\relax}%
\fi}
\def\compressed@list{\relax} % initially empty
\def\compress@cref@command#1{%
\expandafter\let\expandafter\@tempccref\csname#1\endcsname % \@tempa := original
\expandafter\let\csname wantsnodups@#1\endcsname\@tempccref % wants... := \@tempa
% the original, will not see duplicates
\@namedef{#1}##1{%
\protect\IfSubStr{##1}{,}{% unless arg is a list, avoid fuss
\gdef\compressed@list{\relax}%ensure \relax
\forcsvlist\@create@list{##1}%create compressed list
\csname wantsnodups@#1\endcsname{\compressed@list}%pass compressed list to cref
\expandafter\forcsvlist\expandafter\@clear@list\expandafter{\compressed@list}%clear compressed list
}{\csname wantsnodups@#1\endcsname{##1}}}%
}
\compress@cref@command{cref}
\compress@cref@command{Cref}