algorithm2e + cleveref:对行号的错误引用问题

algorithm2e + cleveref:对行号的错误引用问题

由于某些我不明白的原因,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此方法可以正常工作,但是当也加载 时,计数器会使用 进行更新,并且不会侵入 !这也意味着将在所有未(仅)使用 进行操作的计数器上失败。algorithm2ehyperrefhyperrefAlgoLine\stepcountercleverefcleveref\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@refstepcounterhyperref相同的版本),这是出于自身的原因(我认为与避免创建重复的超链接锚点有关)。这是一个不幸的实现选择,因为绕过标准交叉引用机制意味着像 这样的软件包cleveref必须维护脆弱的、专门制作的 的支持algorithm2e。但这就是 LaTeX2e。

加载后hyperrefalgorithm2e必须自行设置\@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

相关内容