Hyperref 改变了索引中“参见”和“另请参阅”的位置。如何恢复?

Hyperref 改变了索引中“参见”和“另请参阅”的位置。如何恢复?

与非常相似的将“另请参阅”放在索引中的页码后面问题,这个问题的不同之处在于它(以及任何解决方案)与结合索引有关hyperref

具有以下 MWE:

\documentclass{report}

\usepackage{makeidx}
\makeindex

\usepackage{hyperref}

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}
  \printindex
\end{document}

不包含该行的索引页输出\usepackage{hyperref}为:

Index
bar, 1
foo, 1, see also bar

最后输出行正确地看到 pageno 位于也可以看看参考。

但是,索引页输出包含以下\usepackage{hyperref}行,错误地/不合需要地重新定位了也可以看看参考页码:

Index
bar, 1
foo, see also bar, 1

问题:我怎样才能鱼与熊掌兼得,即包括hyperref但定位页面之前没有引用也可以看看索引条目文本如输出中所示,不带hyperref

[这不是一个 xindy 问题]

答案1

日志文件中有一个关于正在发生的事情的线索makeindex,其中包含警告:

## Warning (input = test.idx, line = 2; output = test.ind, line = 7):
   -- Conflicting entries: multiple encaps for the same page under same key.

当一个条目在同一页上被索引多次且使用不同的封装(封装页码的命令)时,就会发生这种情况。以下示例说明了这一点:

\documentclass{report}

\usepackage{makeidx}
\makeindex

\newcommand{\zzz}[1]{#1}
\newcommand{\aaa}[1]{#1}

\begin{document}
foo\index{foo|textbf}
\index{foo|zzz}
\index{foo|emph}
\index{foo|aaa}
\index{foo}

\printindex
\end{document}

这会导致四个多重封装警告。该ind文件包含:

\begin{theindex}

  \item foo, 1, \aaa{1}, \emph{1}, \textbf{1}, \zzz{1}

\end{theindex}

makeindex列出了第一页的五个foo条目,但按以下顺序对它们进行了排序:没有 encap(\index{foo}),后跟根据 encap 值按字母顺序排列的其余条目。

现在回到没有 MWE 的情况hyperref

\documentclass{report}

\usepackage{makeidx}
\makeindex

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}
  \printindex
\end{document}

这里第一个和第三个foo索引没有封装(\index{foo}),因此makeindex可以将它们组合成第 1 页的非封装条目,但第二个foo索引有一个封装(\index{foo|seealso{bar}})。封装值为seealso{bar},因此.ind文件包含以下行:

  \item foo, 1, \seealso{bar}{1}

同样,没有封装的条目首先列出。现在让我们添加hyperref

\documentclass{report}

\usepackage{makeidx}
\makeindex

\usepackage{hyperref}

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}
  \printindex
\end{document}

hyperref添加后,会在后台hyperref添加一个封装。您可以通过检查文件来查看,该文件包含以下内容:\index{foo}.idx

\indexentry{foo|hyperpage}{1}
\indexentry{foo|hyperindexformat{\seealso{bar}}}{1}
\indexentry{foo|hyperpage}{1}

再次出现多个封装警告,并makeindex再次根据封装按字母顺序对冲突的条目进行排序,因此.ind文件现在包含:

\item foo, \hyperindexformat{\seealso{bar}}{1}, \hyperpage{1}

这就是导致顺序改变的原因。最简单的解决方案是通过将交叉引用的条目移动到具有不同页码的文档的另一部分来避免多个封装冲突。(由于\seealso忽略了它的第二个参数,实际页码无关紧要。)例如:

\documentclass{report}

\usepackage{makeidx}
\makeindex

\usepackage{hyperref}

\begin{document}
  foo\index{foo}
  foo\index{foo}
  bar\index{bar}

  \clearpage
  \index{foo|seealso{bar}}
  \printindex
\end{document}

这将消除警告并将交叉引用移至位置列表的末尾。

结果图像

编辑:另一种可能性是关闭hyperrefhyperindex选项并创建一个makeindex样式文件,将位置列表包装在可以向页码添加超链接的命令中。例如:

\documentclass{report}

\usepackage{filecontents}
\usepackage{makeidx}
\usepackage[hyperindex=false]{hyperref}

\makeindex

\begin{filecontents}{\jobname.ist}
delim_0 ", \\locationlist\{"
delim_1 ", \\locationlist\{"
delim_2 ", \\locationlist\{"
delim_t "\}"
delim_n ","
encap_prefix "\\encap\{\\"
encap_infix "\{"
encap_suffix "\}\}"
\end{filecontents}

\makeatletter

\newcommand*{\encap}[1]{#1}

\def\@location#1#2\end@location{%
  \ifx\encap#1\relax
    #2%
  \else
    \hyperpage{#1#2}%
  \fi
}

\newcommand*{\locationlist}[1]{%
 \def\locationsep{}%
 \@for\location:=#1\do{%
   \locationsep
   \expandafter\@location\location\end@location
   \def\locationsep{, }%
 }%
}
\makeatother

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}

  \clearpage
  bar\index{bar}

  \clearpage
  bar\index{bar}

  \printindex
\end{document}

如果文件名为test.tex,则需要:

pdflatex test
makeindex -s test.ist -o test.ind test.idx
pdflatex test

索引图像

这适用\hyperpage于普通位置,但不适用于封装。如果您有其他封装(例如\index{foo|textbf}),您将需要一个包装器命令,例如:

\documentclass{report}

\usepackage{filecontents}
\usepackage{makeidx}
\usepackage[hyperindex=false]{hyperref}

\makeindex

\begin{filecontents}{\jobname.ist}
delim_0 ", \\locationlist\{"
delim_1 ", \\locationlist\{"
delim_2 ", \\locationlist\{"
delim_t "\}"
delim_n ","
encap_prefix "\\encap\{\\"
encap_infix "\{"
encap_suffix "\}\}"
\end{filecontents}

\makeatletter

\newcommand*{\encap}[1]{#1}

\def\@location#1#2\end@location{%
  \ifx\encap#1\relax
    #2%
  \else
    \hyperpage{#1#2}%
  \fi
}

\newcommand*{\locationlist}[1]{%
 \def\locationsep{}%
 \@for\location:=#1\do{%
   \locationsep
   \expandafter\@location\location\end@location
   \def\locationsep{, }%
 }%
}
\makeatother

\newcommand*{\primaryidx}[1]{\textbf{\hyperpage{#1}}}

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}

  \clearpage
  bar\index{bar}

  \clearpage
  bar\index{bar}
  foo\index{foo|primaryidx}

  \printindex
\end{document}

得出的结果为:

索引图像

请注意,“另请参阅”部分不在列表末尾,因为它与第 1 页相关联。(假冒页面see中的类似键可以解决这个问题。)如果没有 ,也会出现此问题。glossariesZhyperref

解决此问题的一种方法(如果您不想将\index命令移动到文档末尾)是修改位置解析器,以便它保存交叉引用并将其移动到列表末尾:

\documentclass{report}

\usepackage{filecontents}
\usepackage{makeidx}
\usepackage[hyperindex=false]{hyperref}

\makeindex

\begin{filecontents}{\jobname.ist}
delim_0 ", \\locationlist\{"
delim_1 ", \\locationlist\{"
delim_2 ", \\locationlist\{"
delim_t "\}"
delim_n ","
encap_prefix "\\encap\{\\"
encap_infix "\{"
encap_suffix "\}\}"
\end{filecontents}

\makeatletter

\newcommand*{\encap}[1]{#1}

\def\@ifseealso#1#2\end@ifseealso#3#4{%
  \ifx\seealso#1\relax
   #3%
  \else
   #4%
  \fi
}

\def\@location#1#2\end@location{%
  \ifx\encap#1\relax
    \@ifseealso#2\relax\end@ifseealso
    {\def\crossref{\locationsep #2}}
    {\locationsep #2}%
  \else
    \locationsep
    \hyperpage{#1#2}%
  \fi
}

\newcommand*{\locationlist}[1]{%
 \def\locationsep{}%
 \def\crossref{}%
 \@for\location:=#1\do{%
   \expandafter\@location\location\end@location
   \def\locationsep{, }%
 }%
 \crossref
}
\makeatother

\newcommand*{\primaryidx}[1]{\textbf{\hyperpage{#1}}}

\begin{document}
  foo\index{foo}\index{foo|seealso{bar}}
  foo\index{foo}
  bar\index{bar}

  \clearpage
  bar\index{bar}

  \clearpage
  bar\index{bar}
  foo\index{foo|primaryidx}

  \printindex
\end{document}

索引图像

相关内容