由于某些我不明白的原因,cleveref
对软件包中生成的列表行号的引用产生了错误algorithm2e
。我希望我没有错过一个简单的解决方案...
我的示例如下:
\documentclass[paper=A4, fontsize=11pt]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[linesnumbered]{algorithm2e}
\usepackage{hyperref}
\usepackage{cleveref}
\begin{document}
\begin{algorithm}
Do something\;
Do something else\;\label{line}
\end{algorithm}
line~\ref{line} vs.\ \cref{line}.
\end{document}
输出(您也可以检查在线的) 是
该\ref
命令按预期工作(并引用第 2 行),但该\cref
命令始终引用第 1 行(无论有多少行以及我尝试引用哪一行)。
有人知道解决这个问题的方法吗?
答案1
您发现该包存在疏忽cleveref
。首先,algorithm2e
它使用计数器对行进行编号AlgoLine
,但cleveref
没有跟踪。因此我们需要一个
\crefalias{AlgoLine}{line}
来解决这个问题。
接下来,cleveref
侵入\label
命令以编写另一个标签供自己使用。在您的示例中,.aux
包含
\newlabel{line}{{3}{1}{}{AlgoLine.1.3}{}}
\newlabel{line@cref}{{[line][1][]1}{1}}
第二行由 编写cleveref
。此处有问题的部分是{[line][1][]1}
,这实际上是 的内容\cref@currentlabel
。为什么是错误的?虽然\label
查看\@currentlabel
,但cleveref
会使用其自身\cref@currentlabel
来确定 被标记的内容。为了使 保持最新,cleveref
会侵入\refstepcounter
,并在那里进行更新。当 在没有 的情况下使用时,\cref@currentlabel
此方法可以正常工作,但是当也加载 时,计数器会使用 进行更新,并且不会侵入 !这也意味着将在所有未(仅)使用 进行操作的计数器上失败。algorithm2e
hyperref
hyperref
AlgoLine
\stepcounter
cleveref
cleveref
\refstepcounter
解决方案是入侵\stepcounter
,并\cref@currentlabel
在那里进行更新。这样做的代码与 相同\refstepcounter
。完整的代码如下
\documentclass[paper=A4, fontsize=11pt]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[linesnumbered]{algorithm2e}
\usepackage{hyperref}
\usepackage{cleveref}
\crefalias{AlgoLine}{line}%
\makeatletter
\let\cref@old@stepcounter\stepcounter
\def\stepcounter#1{%
\cref@old@stepcounter{#1}%
\cref@constructprefix{#1}{\cref@result}%
\@ifundefined{cref@#1@alias}%
{\def\@tempa{#1}}%
{\def\@tempa{\csname cref@#1@alias\endcsname}}%
\protected@edef\cref@currentlabel{%
[\@tempa][\arabic{#1}][\cref@result]%
\csname p@#1\endcsname\csname the#1\endcsname}}
\makeatother
\begin{document}
\begin{algorithm}
Do something\;
Do more\;
Do something else\;\label{line}
\end{algorithm}
line~\ref{line} vs.\ \cref{line}
\end{document}
答案2
mafp 的解决方案是一个坏主意,应该避免。黑客\stepcounter
绝对是错误的做法,因为它被用来执行与交叉引用无关的各种计数器。交叉引用计数器應該始终按照 进行\refstepcounter
,它还负责\@currentlabel
适当设置。因此,“仅监控\refstepcounter
”是正确的做法。大多数与交叉引用相关的打包 ( hyperref
, varioref
...) 都以这种方式工作。
不幸的是,当hyperref
加载时,algorithm2e
会绕过\refstepcounter
和\H@refstepcounter
(hyperref
相同的版本),这是出于自身的原因(我认为与避免创建重复的超链接锚点有关)。这是一个不幸的实现选择,因为绕过标准交叉引用机制意味着像 这样的软件包cleveref
必须维护脆弱的、专门制作的 的支持algorithm2e
。但这就是 LaTeX2e。
加载后hyperref
,algorithm2e
必须自行设置\@currentlabel
(因为它会绕过\refstepcounter
)。正确的解决方案是进行修改algorithm2e
,使其\cref@currentlabel
与同时设置\@currentlabel
。最新版本cleveref
(0.18.8)包含对此问题的修复。
如果人们向软件包作者报告此类错误,而不是仅仅将它们发布到 stackexchange 并使用回复中建议的任何丑陋的解决方法,那将会很有帮助。这样,软件包本身就可以修复错误,每个人都会受益。
答案3
hyperref
我找到了一个解决+algorithm2e
行号不兼容问题的简单方法。只需使用\nllabel
而不是\label
。对我来说很管用。感谢 Karthik:http://martinharrigan.blogspot.com.br/2007/11/using-hyperref-and-algorithm2e-line.html