![使用 hyperref 对算法中的某行进行了错误引用](https://linux22.com/image/280446/%E4%BD%BF%E7%94%A8%20hyperref%20%E5%AF%B9%E7%AE%97%E6%B3%95%E4%B8%AD%E7%9A%84%E6%9F%90%E8%A1%8C%E8%BF%9B%E8%A1%8C%E4%BA%86%E9%94%99%E8%AF%AF%E5%BC%95%E7%94%A8.png)
我正在使用algpseudocode
和algorithm
包来排版伪代码。我也使用float
、hyperref
和caption
包。问题是,当我引用伪代码中的一行时,数字是正确的,但当我单击它时,文档会移动到章节的开头,而不是算法。
最小示例:
\documentclass{book}
\usepackage{blindtext}
\usepackage{float}
\usepackage{hyperref}
\usepackage[hypcap]{caption}
\usepackage{algpseudocode}
\usepackage[chapter]{algorithm}
\begin{document}
\chapter{Heading}
Reference to the line \ref{line}.
\Blindtext
\begin{algorithm}
\begin{algorithmic}[1]
\State Statement \label{line}
\end{algorithmic}
\caption{Example}
\label{alg}
\end{algorithm}
\Blindtext
\end{document}
答案1
有两种方法可以做到这一点。如前所述,只需加载新版本即可cleveref
部分解决问题,链接现在指向行号而不是章节的开头;但当有两个或多个算法时,hyperref
链接不会区分不同算法中的相同行号。最简单的解决方案是通过hyperref
加载
\usepackage[hypertexnames=false]{hyperref}
这会将所有链接名称更改为唯一但无法被人类识别/有意义的名称。如果您认为这是一种愚蠢的方法,那么您可以\theHALG@line
通过以下方式适当定义以提供唯一链接:
\providecommand\theHALG@line{\thealgorithm.\arabic{ALG@line}}
在hyperref
每个实例中\thecounter
都有一个对应\theHcounter
的可重新定义的创建唯一标识符。在您的实例中,它algorithm
为您的环境提供了一个唯一的容器algorithmic
,因此可以使用其数字表示来区分不同的实例。
由于@
上述命令名称中的符号,您必须将此代码放在\makeatletter
和之间\makeatother
:
\documentclass{book}
\usepackage{lipsum}
\usepackage{algpseudocode}
\usepackage{float}
\usepackage[chapter]{algorithm}
\usepackage[hypcap]{caption}
\usepackage{hyperref}
\usepackage{cleveref}
\makeatletter
\providecommand\theHALG@line{\thealgorithm.\arabic{ALG@line}}
\makeatother
\begin{document}
\chapter{Heading}
Here's the first test to line \ref{test1} of Algorithm \ref{alg1}.\\
Here's the second test to line \ref{test2} of Algorithm \ref{alg1}.
Here's the first test to line \ref{test21} of Algorithm \ref{alg2}.\\
Here's the second test to line \ref{test22} of Algorithm \ref{alg2}.
\begin{algorithm}[p]
\begin{algorithmic}[1]
\State Statement
\State Statement
\State Statement
\State Statement \label{test1}
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement \label{test2}
\State Statement
\end{algorithmic}
\caption{Example}
\label{alg1}
\end{algorithm}
\begin{algorithm}[p]
\begin{algorithmic}[1]
\State Statement
\State Statement
\State Statement
\State Statement \label{test21}
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement \label{test22}
\State Statement
\end{algorithmic}
\caption{Example}
\label{alg2}
\end{algorithm}
\end{document}
答案2
这好像是algorithmicx
没有采取hyperref
考虑到,至少没有完全考虑到……
该宏\ALG@step
负责写出行号(取自algorithmicx.sty
):
\def\ALG@step%
{%
\addtocounter{ALG@line}{1}%
\addtocounter{ALG@rem}{1}%
\ifthenelse{\equal{\arabic{ALG@rem}}{\ALG@numberfreq}}%
{\setcounter{ALG@rem}{0}\alglinenumber{\arabic{ALG@line}}}%
{}%
}%
注意行号是如何使用 来分级的\addtocounter{ALG@line}{1}
。这不会设置超目标 - 链接可以跳转到的锚点。在里面,它应该使用\refstepcounter{ALG@line}
。如果你在前言中使用/添加
\makeatletter
\def\ALG@step%
{%
\refstepcounter{ALG@line}% Step and anchor for hyperref
\stepcounter{ALG@rem}% Regular step (equivalent to \addtocounter{ALG@rem}{1})
\ifthenelse{\equal{\arabic{ALG@rem}}{\ALG@numberfreq}}%
{\setcounter{ALG@rem}{0}\alglinenumber{\arabic{ALG@line}}}%
{}%
}%
\makeatother
你的超链接应该可以正常工作。
应该提到的是,algorithmic
环境的可选参数旨在显示带有步骤的行号。例如,它允许只显示每隔一个行号。当算法中没有明显标记第 2 行时,跳转到(例如)第 2 行似乎很奇怪。上述调整允许这样做。
答案3
使用\hypertarget
和\hyperlink
:
\documentclass{book}
\usepackage{blindtext}
\usepackage{algpseudocode}
\usepackage{float}
\usepackage[hypcap]{caption}
\usepackage{hyperref}
\usepackage[chapter]{algorithm}
\begin{document}
\chapter{Heading}
Reference to the line 1 of Alg. \hyperlink{line}{\ref{alg1}}.
Reference to the line 8 of Alg. \hyperlink{line8}{\ref{alg1}}.
\Blindtext
\begin{algorithm}
\begin{algorithmic}[1]\hypertarget{line}{}
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement
\State Statement \hypertarget{line8}{}
\State Statement
\end{algorithmic}
\caption{Example}\label{alg1}
\label{alg}
\end{algorithm}
\Blindtext
\end{document}
答案4
\phantomsection
我采用了一个最初由@Herbert构思的想法,并将其用于我的答案中。这个想法是在each之前使用,\label
它指的是算法的某行。由于这种重复模式需要定义一个新的宏,我定义\plabel
如下:
\newcommand\plabel[1]{\phantomsection\label{#1}}
这是一个最小的工作示例:
\documentclass{book}
\usepackage{lipsum}
\usepackage{algpseudocode}
\usepackage{float}
\usepackage[hypcap]{caption}
\usepackage{hyperref}
\usepackage[chapter]{algorithm}
\newcommand\plabel[1]{\phantomsection\label{#1}}
\begin{document}
\chapter{Heading}
Here's the first test to line \ref{test1} of Algorithm \ref{alg}.\\
Here's the second test to line \ref{test2} of Algorithm \ref{alg}.
\begin{algorithm}[p]
\begin{algorithmic}[1]
\State Statement
\State Statement
\State Statement
\State Statement \plabel{test1}
\State Statement
\State Statement
\State Statement \plabel{test2}
\State Statement
\end{algorithmic}
\caption{Example}\label{alg1}
\label{alg}
\end{algorithm}
\end{document}