![标签/参考机制的评估问题](https://linux22.com/image/397946/%E6%A0%87%E7%AD%BE%2F%E5%8F%82%E8%80%83%E6%9C%BA%E5%88%B6%E7%9A%84%E8%AF%84%E4%BC%B0%E9%97%AE%E9%A2%98.png)
我正在定义一个computation
定义一堆方程的环境。每个方程都有一个数字,我想打印该数字。为了自动生成正确的数字,我使用了 LaTeX 的标签/引用机制。这是我的代码:
\documentclass{article}
\usepackage{hyperref}
\newcounter{cp}
\newcommand{\rcp}[1]{\refstepcounter{cp}\label{\ctmp:#1}}
\newcommand{\cref}[1]{\ref{\ctmp:#1}}
\newenvironment{computation}[1]{
\def\ctmp{#1}
\begin{tabular}{lc|lc}
}
{
\end{tabular}
\setcounter{cp}{0}
}
\newcommand{\addeq}[4]{
\rcp{#1}\((\thecp{})\) & #2 & #3 & #4\\
}
\begin{document}
\begin{computation}{first}
\addeq{cp:1}{foo}{justification of foo}{}
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\cref{cp:1}}
\end{computation}
\clearpage
\begin{computation}{second}
\addeq{cp:1}{foo}{justification of foo}{}
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\cref{cp:1}} % here the reference is bad.
\end{computation}
\end{document}
我遇到的问题是,每次我引用一个方程式时,都会打印正确的数字,但在 PDF 上,链接会将我送回computation
第一次使用宏的方程式,而不是当前的计算环境。
我认为这与 LaTeX 的评估机制有关,但我没有发现我的错误。
答案1
您还会在终端和 .log 文件中看到一些该模式的错误消息:
pdfTeX warning (ext4): destination with the same identifier (name{cp.1}) has been already used, duplicate ignored
原因在于你的环境的结束部分中的computaion
以下行\setcounter{cp}{0}
:
当\rcp
执行时,\refstepcounter{cp}
也执行。当使用 时hyperref
,\refstepcounter{cp}
反过来也会为超链接创建一个目标。该目标有一个名称。默认情况下,该名称既来自名称,也来自计数器 的值cp
。计数器的值cp
是通过扩展宏 获得的\theHcp
。因此,如果 的值在某个时候cp
重置为0
,则不再能确保超链接目标名称的唯一性。
您需要确保超链接目的地名称的唯一性。您可以通过重新定义\theHcp
来实现这一点,这样重置计数器cp
就不会影响超链接目的地名称的唯一性。
一种可能性是同时计算 -environment 的实例数computation
,并将相应 -environment 的编号也添加computation
到 的扩展中\theHcp
。在下面的示例中,这是通过一个宏来实现的\ThisCpmputationinstance
,该宏对于computation
-environment 的每个实例仅在该实例形成的范围内定义。之所以这样做,是因为\stepcounter
和 是\refstepcounter
全局工作的,这意味着\arabic{computationinstance}
如果存在computation
-environment 的嵌套实例,直接使用 可能会让事情变得奇怪。
除此之外,您可能还希望对由于以下原因创建的超链接目标的垂直放置进行一些处理\refstepcounter
:
实际上,目的地将垂直放置在其所在框的基线上。
因此,单击超链接将(垂直)将相应框的基线滚动到查看 .pdf 文件的窗口的顶部。因此,您将看不到基线上方的字形/字母等部分。
因此,使用 hyperref 包,需要进行额外的工作以确保\baselineskip
如果 LaTeX 未处于垂直模式,目的地将垂直向上移动(这是两个连续文本行的基线之间的距离)。
通常这很好。但不是在tabular
-环境中,因为在这些环境中\baselineskip
是 0,这意味着向上移动 0,这意味着通过单击链接导航到相应的目的地最终会将相应框的基线滚动到查看 .pdf 文件的窗口的顶部。这意味着看不到该框中基线上方的字形部分。
我建议在这些环境中使用的尺寸,\strutbox
而不是使用\baselineskip
。
在下面的例子中,我%
在这里和那里添加了一些,以防止出现不需要的/不需要的空间标记。
\documentclass{article}
\usepackage{hyperref}
\newcounter{cp}
\newcounter{computationinstance}
\newcommand{\ThisCpmputationinstance}{}%
\edef\ThisCpmputationinstance{\arabic{computationinstance}}
\renewcommand{\theHcp}{\ThisCpmputationinstance.\arabic{cp}}
\newcommand\savedHyperRaiseLinkHook{}
\newcommand{\rcp}[1]{%
%\ifvmode\leavevmode\fi
\let\savedHyperRaiseLinkHook\HyperRaiseLinkHook
\def\HyperRaiseLinkHook{%
% Usually \HyperRaiseLinkLength equals \baselineskip but
% \baselineskip is 0 inside tabulars, thus let's use
% the dimensions of the strutbox instead:
\setlength\HyperRaiseLinkLength{\ht\strutbox}%
\addtolength\HyperRaiseLinkLength{\dp\strutbox}%
}%
\refstepcounter{cp}%
\let\HyperRaiseLinkHook\savedHyperRaiseLinkHook
\label{\ctmp:#1}}%
\newcommand{\MYcref}[1]{\ref{\ctmp:#1}}
\newcommand{\ctmp}{}%
\newenvironment{computation}[1]{%
\stepcounter{computationinstance}%
\edef\ThisCpmputationinstance{\arabic{computationinstance}}%
\def\ctmp{#1}%
\begin{tabular}{lc|lc}%
}{%
\end{tabular}%
\setcounter{cp}{0}%
}
\newcommand{\addeq}[4]{%
\rcp{#1}\((\thecp{})\)\\%
}%
\begin{document}
\begin{computation}{first}%
\addeq{cp:1}{foo}{justification of foo}{}%
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\MYcref{cp:1}}%
\end{computation}
\clearpage
\begin{computation}{second}%
\addeq{cp:1}{foo}{justification of foo}{}%
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\MYcref{cp:1}}% here the reference is okay now.
\end{computation}
\end{document}
只要确保环境的两个实例都没有相同的名称,并且没有环境实例名称包含危险的(非字符)标记,您就可以通过添加扩展来computation
确保超链接目的地名称的唯一性:\ctmp
\theHcp
\documentclass{article}
\usepackage{hyperref}
\newcounter{cp}
\renewcommand{\theHcp}{\ctmp.\arabic{cp}}
\newcommand\savedHyperRaiseLinkHook{}
\newcommand{\rcp}[1]{%
%\ifvmode\leavevmode\fi
\let\savedHyperRaiseLinkHook\HyperRaiseLinkHook
\def\HyperRaiseLinkHook{%
% Usually \HyperRaiseLinkLength equals \baselineskip but
% \baselineskip is 0 inside tabulars, thus let's use
% the dimensions of the strutbox instead:
\setlength\HyperRaiseLinkLength{\ht\strutbox}%
\addtolength\HyperRaiseLinkLength{\dp\strutbox}%
}%
\refstepcounter{cp}%
\let\HyperRaiseLinkHook\savedHyperRaiseLinkHook
\label{\ctmp:#1}}%
\newcommand{\MYcref}[1]{\ref{\ctmp:#1}}
\newcommand{\ctmp}{}%
\def\ctmp.{}%
\newenvironment{computation}[1]{%
\def\ctmp{#1}%
\begin{tabular}{lc|lc}%
}{%
\end{tabular}%
\setcounter{cp}{0}%
}
\newcommand{\addeq}[4]{%
\rcp{#1}\((\thecp{})\)\\%
}%
\begin{document}
\begin{computation}{first}%
\addeq{cp:1}{foo}{justification of foo}{}%
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\MYcref{cp:1}}%
\end{computation}
\clearpage
\begin{computation}{second}%
\addeq{cp:1}{foo}{justification of foo}{}%
\hline
\addeq{cp:2}{bla}{justification of bla (using foo)}{\MYcref{cp:1}}% here the reference is okay now.
\end{computation}
\end{document}