我怎样才能让 cleveref 压缩对同一部分的多个引用?

我怎样才能让 cleveref 压缩对同一部分的多个引用?

编辑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@getlabelcleveref\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}需要一些\expandafters(或者可以直接经过#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}

相关内容