使用 hyperref 和 backref 精确反向引用目标

使用 hyperref 和 backref 精确反向引用目标

backref选项及其hyperref软件包中的变体允许包括反向引用在参考书目中页数或者部分其中引用了给定的参考文献。

反向引用的目标是开始出现引用的页面(或部分,取决于选项)(请参阅 backref 手册)。

我怎样才能使反向引用链接精确指向文本中出现引用键的行?

显然,有人有一个相关问题页面侧面写着“跑步者”,但解决方案取决于跑步者本身的定义。

我希望在反向引用中获得与文内引用到参考文献的链接相同的行为(即指向所讨论的参考文献的行),只是向后。

任何建议都将受到赞赏。

编辑 下面是一个最小的工作示例:文内引用在页面中均匀分布,参考书目中的反向引用命令应该指向它们,而不是页面顶部。

\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}   

\usepackage[pagebackref]{hyperref}   

\begin{document}
Top of page
\vfill
\cite{Cleveland2007}
\vfill
\cite{Spence1999}

\newpage

\begin{thebibliography}{2}
\providecommand{\natexlab}[1]{#1}
\providecommand{\url}[1]{\texttt{#1}}
\expandafter\ifx\csname urlstyle\endcsname\relax
  \providecommand{\doi}[1]{doi: #1}\else
  \providecommand{\doi}{doi: \begingroup \urlstyle{rm}\Url}\fi

\bibitem[Cleveland(1984)]{Cleveland2007}
WS~Cleveland.
\newblock {Graphical perception: Theory, experimentation, and application to
  the development of graphical methods}.
\newblock \emph{Journal of the American Statistical Association}, 79\penalty0
  (387):\penalty0 531--554, 1984.

\bibitem[Spence et~al.(1999)Spence, Kutlesa, and Rose]{Spence1999}
I.~Spence, N.~Kutlesa, and D.L. Rose.
\newblock {Using color to code quantity in spatial analysis}.
\newblock \emph{Journal of Experimental Psychology: Applied}, 5:\penalty0 393,
  1999.

\end{thebibliography}
\end{document}

我使用 Pdflatex 编译了两次。

答案1

该补丁主要由三个部分组成。

  1. \phantomsection在 every 之前添加一个\cite即可完成大部分工作。这些幻像部分是超链接指向的内容。
  2. backref即使使用页码作为标签,也要确信超链接指向幻影部分。
  3. backref如果它认为没有可以指向的部分,就不要让我们的超目标被超越(而是使用文档的开头)。

该补丁现已更新,希望在所有情况下都能正常工作,无论是否使用natbib。请参阅帖子历史natbib如果对支持不感兴趣。请注意,biblatex提供自己的backref模式,但不提供直接链接,并且此补丁在那里不起作用(不应使用!)

补丁代码(在加载hyperref带有backref选项的软件包后在文档前言中使用;请注意这一点将要如果没有!则失败hyperref):

%%%% these patches ensure that the backrefs point to the actual occurrences of the citations in the text, not just the page or section in which they appeared
%%%% https://tex.stackexchange.com/questions/54541/precise-back-reference-target-with-hyperref-and-backref
%%%% BEGIN BACKREF DIRECT PATCH, apply these AFTER loading hyperref package with appropriate backref option
% The following options are provided for the patch, currently with a poor interface!
% * If there are multiple cites on the same (page|section) (depending on backref mode),
%   should we show only the first one or should we show them all?
\newif\ifbackrefshowonlyfirst
\backrefshowonlyfirstfalse
%\backrefshowonlyfirsttrue
%%%% end of options
%
% hyperref is essential for this patch to make any sense, so it is not unreasonable to request it be loaded before applying the patch
\makeatletter
% 1. insert a phantomsection before every cite, so hyperref has something to target
%    * in case natbib is loaded. hyperref provides an appropriate hook so this should be safe, and we don't even need to check if natbib is loaded!
\let\BR@direct@old@hyper@natlinkstart\hyper@natlinkstart
\renewcommand*{\hyper@natlinkstart}{\phantomsection\BR@direct@old@hyper@natlinkstart}% note that the anchor will appear after any brackets at the start of the citation, but that's not really a big issue?
%    * if natbib isn't used, backref lets \@citex to \BR@citex during \AtBeginDocument
%      so just patch \BR@citex
\let\BR@direct@oldBR@citex\BR@citex
\renewcommand*{\BR@citex}{\phantomsection\BR@direct@oldBR@citex}%

% 2. if using page numbers, show the page number but still hyperlink to the phantomsection instead of just the page!
\long\def\hyper@page@BR@direct@ref#1#2#3{\hyperlink{#3}{#1}}

% check which package option the user loaded (pages (hyperpageref) or sections (hyperref)?)
\ifx\backrefxxx\hyper@page@backref
    % they wanted pages! make sure they get our re-definition
    \let\backrefxxx\hyper@page@BR@direct@ref
    \ifbackrefshowonlyfirst
        %\let\backrefxxxdupe\hyper@page@backref% test only the page number
        \newcommand*{\backrefxxxdupe}[3]{#1}% test only the page number
    \fi
\else
    \ifbackrefshowonlyfirst
        \newcommand*{\backrefxxxdupe}[3]{#2}% test only the section name
    \fi
\fi

% 3. now make sure that even if there is no numbered section, the hyperref's still work instead of going to the start of the document!
\RequirePackage{etoolbox}
\patchcmd{\Hy@backout}{Doc-Start}{\@currentHref}{}{\errmessage{I can't seem to patch backref}}
\makeatother
%%%% END BACKREF PATCHES

所有这些都在 MWE 的上下文中(基于提供的 MWE,但进行了扩展),现在使用biblio.bib示例文件希望能够自动找到它(否则请使用链接从 CTAN 获取):

\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{natbib}
\bibliographystyle{plainnat}
\usepackage[backref=page]{hyperref}

%%%% these patches ensure that the backrefs point to the actual occurrences of the citations in the text, not just the page or section in which they appeared
%%%% https://tex.stackexchange.com/questions/54541/precise-back-reference-target-with-hyperref-and-backref
%%%% BEGIN BACKREF DIRECT PATCH, apply these AFTER loading hyperref package with appropriate backref option
% The following options are provided for the patch, currently with a poor interface!
% * If there are multiple cites on the same (page|section) (depending on backref mode),
%   should we show only the first one or should we show them all?
\newif\ifbackrefshowonlyfirst
\backrefshowonlyfirstfalse
%\backrefshowonlyfirsttrue
%%%% end of options
%
% hyperref is essential for this patch to make any sense, so it is not unreasonable to request it be loaded before applying the patch
\makeatletter
% 1. insert a phantomsection before every cite, so hyperref has something to target
%    * in case natbib is loaded. hyperref provides an appropriate hook so this should be safe, and we don't even need to check if natbib is loaded!
\let\BR@direct@old@hyper@natlinkstart\hyper@natlinkstart
\renewcommand*{\hyper@natlinkstart}{\phantomsection\BR@direct@old@hyper@natlinkstart}% note that the anchor will appear after any brackets at the start of the citation, but that's not really a big issue?
%    * if natbib isn't used, backref lets \@citex to \BR@citex during \AtBeginDocument
%      so just patch \BR@citex
\let\BR@direct@oldBR@citex\BR@citex
\renewcommand*{\BR@citex}{\phantomsection\BR@direct@oldBR@citex}%

% 2. if using page numbers, show the page number but still hyperlink to the phantomsection instead of just the page!
\long\def\hyper@page@BR@direct@ref#1#2#3{\hyperlink{#3}{#1}}

% check which package option the user loaded (pages (hyperpageref) or sections (hyperref)?)
\ifx\backrefxxx\hyper@page@backref
    % they wanted pages! make sure they get our re-definition
    \let\backrefxxx\hyper@page@BR@direct@ref
    \ifbackrefshowonlyfirst
        %\let\backrefxxxdupe\hyper@page@backref% test only the page number
        \newcommand*{\backrefxxxdupe}[3]{#1}% test only the page number
    \fi
\else
    \ifbackrefshowonlyfirst
        \newcommand*{\backrefxxxdupe}[3]{#2}% test only the section name
    \fi
\fi

% 3. now make sure that even if there is no numbered section, the hyperref's still work instead of going to the start of the document!
\RequirePackage{etoolbox}
\patchcmd{\Hy@backout}{Doc-Start}{\@currentHref}{}{\errmessage{I can't seem to patch backref}}
\makeatother
%%%% END BACKREF PATCHES

\begin{document}
Top of page. No sections at all here yet.
\vfill
\cite{GSM97}
\vfill
\cite{Lam94}
\section*{Unnumbered}
Check that things work in unnumbered sections.

\cite{Lam94}

\newpage
\section{Numbered}
And in numbered sections!

This is just a test \citep{GSM97} on another page and not at the start of the line to see how well things work.

And other citation to something already cited \cite{GSM97} on the same page in the same section.

\section{Another numbered one}
And another dupe test \citet{GSM97}.

\newpage
\bibliography{biblio}
\end{document}

请注意,此示例使用\citet\citepnatbib检查它们是否按预期工作。

相关内容